home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1991-05-01 | 132.2 KB | 4,891 lines | [ TEXT/MPS ]
// UApplication.cp // Copyright © 1984-1991 by Apple Computer Inc. All rights reserved. #ifndef __UAPPLICATION__ #include <UApplication.h> #endif #ifndef __STDIO__ #include <StdIo.h> #endif #ifndef __UGEOMETRY__ #include <UGeometry.h> #endif #ifndef __UBEHAVIOR__ #include <UBehavior.h> #endif #ifndef __UFILE__ #include <UFile.h> #endif #ifndef __UAPPLEEVENTS__ #include <UAppleEvents.h> #endif #ifndef __UPRINTHANDLER__ #include <UPrintHandler.h> #endif #ifndef __UWINDOW__ #include <UWindow.h> #endif #ifndef __USCROLLER__ #include <UScroller.h> #endif #ifndef __UFILEBASEDDOCUMENT__ #include <UFileBasedDocument.h> #endif #ifndef __UMACAPPUTILITIES__ #include <UMacAppUtilities.h> #endif #ifndef __UERRORMGR__ #include <UErrorMgr.h> #endif #ifndef __UMEMORY__ #include <UMemory.h> #endif #ifndef __UMENUMGR__ #include <UMenuMgr.h> #endif #ifndef __UMACAPPGLOBALS__ #include <UMacAppGlobals.h> #endif #ifndef __ERRORS__ #include <Errors.h> #endif #ifndef __TOOLUTILS__ #include <ToolUtils.h> #endif #ifndef __UBUSYCURSOR__ #include <UBusyCursor.h> #endif #ifndef __UDEBUG__ #include <UDebug.h> #endif #ifndef __UINSPECTOR__ #include <UInspector.h> #endif #ifndef __UCLIPBOARDMGR__ #include <UClipboardMgr.h> #endif #ifndef __RESOURCES__ #include <Resources.h> #endif #ifndef __DESK__ #include <Desk.h> #endif #ifndef __PACKAGES__ #include <Packages.h> #endif #ifndef __SCRIPT__ #include <Script.h> #endif #ifndef __DISKINIT__ #include <DiskInit.h> #endif #ifndef __OSEVENTS__ #include <OSEvents.h> #endif #ifndef __ULOMEM__ #include <ULoMem.h> #endif #ifndef __STDLIB__ #include <StdLib.h> #endif #ifndef __UVIEWSERVER__ #include <UViewServer.h> #endif #ifndef __UTABBEHAVIORS__ #include <UTabBehaviors.h> #endif //-------------------------------------------------------------------------------------------------- TApplication* gApplication = NULL; Boolean gInitialized = FALSE; AEAddressDesc gServerAddress; //-------------------------------------------------------------------------------------------------- #pragma segment MAViewRes CDocumentIterator::CDocumentIterator(TApplication* itsApplication, ArrayIndex itsLowBound, ArrayIndex itsHighBound, Boolean itsForward) : CObjectIterator(itsApplication ? itsApplication->fDocList : NULL, itsLowBound, itsHighBound, itsForward) { } //-------------------------------------------------------------------------------------------------- #pragma segment MAViewRes CDocumentIterator::CDocumentIterator(TApplication* itsApplication, Boolean itsForward) : CObjectIterator(itsApplication ? itsApplication->fDocList : NULL, itsForward) { } //-------------------------------------------------------------------------------------------------- #pragma segment MAViewRes CDocumentIterator::CDocumentIterator(TApplication* itsApplication) : CObjectIterator(itsApplication ? itsApplication->fDocList : NULL) { } //-------------------------------------------------------------------------------------------------- #pragma segment MAViewRes TDocument* CDocumentIterator::CurrentDocument(void) { return (TDocument*)this->CurrentObject(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAViewRes TDocument* CDocumentIterator::FirstDocument(void) { return (TDocument*)this->FirstObject(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAViewRes TDocument* CDocumentIterator::NextDocument(void) { return (TDocument*)this->NextObject(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal short TEventList::Compare(TObject* item1, TObject* item2) { // We want higher priority events at the end of the queue so we can delete from the end of the list // This will save us a block move in DeleteElementsAt. if (((TEvent *)item1)->fPriority > ((TEvent *)item2)->fPriority) return kItem1LessThanItem2; else if (((TEvent *)item1)->fPriority < ((TEvent *)item2)->fPriority) return kItem1GreaterThanItem2; else return kItem1EqualItem2; } //-------------------------------------------------------------------------------------------------- #pragma segment MAInit pascal void TEventList::IEventList(void) { this->ISortedList(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TEventList::Insert(TObject* item) // override { Boolean oldObjectPerm; ArrayIndex anEqualItem; ArrayIndex lastEqualItem; ArrayIndex i; // Guarantee that the insertion can take place oldObjectPerm = AllocateObjectsFromPerm(FALSE); // !!! the search alg. should support this. Performance will degrade here for // big queues (shouldn't happen often, but come back and fix the general case anyways) anEqualItem = this->GetEqualItemNo(item); // If any equal items were found then find the _last_ equal item if (anEqualItem != kEmptyIndex) { lastEqualItem = anEqualItem; // Tentative value for (i = (anEqualItem + 1); i <= this->GetSize(); ++i)// ??? what about kMaxArrayIndex? if (this->Compare(this->At(i), item) == kItem1EqualItem2) lastEqualItem = i; else break; // InsertBefore is not available to a sorted list this->InsertElementsBefore(lastEqualItem + 1, (Ptr)item, 1); } else inherited::Insert(item); AllocateObjectsFromPerm(oldObjectPerm); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void TEventList::Fields(TObject* obj) // override { obj->DoToField("TEventList", (Ptr)NULL, bClass); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #if qDebug #pragma segment MADebugger pascal void TDebugCommand::DoIt(void) { EnterMacAppDebugger(); } #endif //-------------------------------------------------------------------------------------------------- #if qDebug #pragma segment MASelCommand pascal void TDebugCommand::IDebugCommand(CmdNumber itsCmdNumber) { this->INoChangesCommand(itsCmdNumber, NULL, NULL); } #endif //-------------------------------------------------------------------------------------------------- #if qDebug #pragma segment MAFields pascal void TDebugCommand::Fields(TObject* obj) // override { obj->DoToField("TDebugCommand", (Ptr)NULL, bClass); inherited::Fields(obj); } #endif //-------------------------------------------------------------------------------------------------- #if qInspector #pragma segment MAInspector pascal void TInspectorCommand::DoIt(void) { MakeInspectorWindow(); } #endif //-------------------------------------------------------------------------------------------------- #if qInspector #pragma segment MASelCommand pascal void TInspectorCommand::IInspectorCommand(CmdNumber itsCmdNumber) { this->INoChangesCommand(itsCmdNumber, NULL, NULL); } #endif //-------------------------------------------------------------------------------------------------- #if qInspector #pragma segment MAFields pascal void TInspectorCommand::Fields(TObject* obj)// override { obj->DoToField("TInspectorCommand", (Ptr)NULL, bClass); inherited::Fields(obj); } #endif //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TQuitCommand::DoIt(void) { FailInfo fi; if (fi.Try()) { gApplication->fAppDone = TRUE; gApplication->Close(); fi.Success(); } else // Recover { gApplication->fAppDone = FALSE; fi.ReSignal(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAInit pascal void TQuitCommand::IQuitCommand(CmdNumber itsCmdNumber) { this->INoChangesCommand(itsCmdNumber, NULL, NULL); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void TQuitCommand::Fields(TObject* obj) // override { obj->DoToField("TQuitCommand", (Ptr)NULL, bClass); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TUndoRedoCommand::DoIt(void) { TCommand * lastCommand; lastCommand = gApplication->GetTarget()->GetLastCommand(); if (lastCommand->fChangesClipboard) gClipboardMgr->SwapClipViews(); if (lastCommand->fCmdDone) lastCommand->UndoIt(); else lastCommand->RedoIt(); lastCommand->fCmdDone =!lastCommand->fCmdDone; if (lastCommand->fCausesChange) // put this after .UndoIt/.RedoIt, so they // can change the flag if (lastCommand->fChangedObject) // Notify the proper object that a change has occurred lastCommand->fChangedObject->Changed(lastCommand->GetChangeID(), lastCommand); } //-------------------------------------------------------------------------------------------------- #pragma segment MAInit pascal void TUndoRedoCommand::IUndoRedoCommand(CmdNumber itsCmdNumber) { this->INoChangesCommand(itsCmdNumber, NULL, NULL); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void TUndoRedoCommand::Fields(TObject* obj)// override { obj->DoToField("TUndoRedoCommand", (Ptr)NULL, bClass); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal void TNewDocCommand::DoIt(void) { gApplication->OpenNew(fID); } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TNewDocCommand::INewDocCommand(CmdNumber itsCmdNumber) { this->INoChangesCommand(itsCmdNumber, NULL, NULL); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void TNewDocCommand::Fields(TObject* obj)// override { obj->DoToField("TNewDocCommand", (Ptr)NULL, bClass); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TFilesCommand::IFilesCommand(CmdNumber itsCmdNumber, TList* theDocuments) { this->IAppleCommand(itsCmdNumber, NULL, NULL); fFileList = theDocuments; } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TFilesCommand::InitFromAppleEvent(CmdNumber itsCmdNumber, TDocument* itsDocument, TView* itsView, const AppleEvent& itsMessage, const AppleEvent& itsReply)// override { THandleList * aHandleList = NULL; TList * aFileList = NULL; FailInfo fi; VOLATILE(aHandleList); VOLATILE(aFileList); inherited::InitFromAppleEvent(itsCmdNumber, itsDocument, itsView, itsMessage, itsReply); if (fi.Try()) { aHandleList = new THandleList; aHandleList->IHandleList(); aFileList = NewList(); fMessage->ReadHandleList(keyDirectObject, typeAlias, aHandleList); // Block is necessary for correct failure handling { CHandleIterator iter(aHandleList); for (Handle item = iter.FirstHandle(); iter.More(); item = iter.NextHandle()) { TFile * aFile; aFile = gApplication->DoMakeFile(itsCmdNumber); FailOSErr(aFile->IdentifyByAlias(AliasHandle(item))); aFileList->InsertLast(aFile); item = DisposeIfHandle(item); } } fi.Success(); } else // Recover { aHandleList = (THandleList *)(FreeIfObject(aHandleList)); aFileList = (TList *)(FreeIfObject(aFileList)); fi.ReSignal(); } aHandleList->Free(); // It is just a list of disposed handles… fFileList = aFileList; } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TFilesCommand::Initialize(void) // override { inherited::Initialize(); fCausesChange = FALSE; fFileList = NULL; } //-------------------------------------------------------------------------------------------------- #pragma segment MAClose pascal void TFilesCommand::Free(void) // override { fFileList = (TList *)(FreeIfObject(fFileList)); inherited::Free(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void TFilesCommand::Fields(TObject* obj) // override { obj->DoToField("TFilesCommand", (Ptr)NULL, bClass); obj->DoToField("fFileList", (Ptr) & fFileList, bObject); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TODocCommand::IODocCommand(CmdNumber itsCmdNumber, TList* theDocuments) { this->IFilesCommand(itsCmdNumber, theDocuments); } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal void TODocCommand::DoIt(void) // override { FailInfo fi; if (fi.Try()) { { CObjectIterator iter(fFileList); for (TFile* aFile = (TFile*)iter.FirstObject(); iter.More(); aFile = (TFile*)iter.NextObject()) gApplication->OpenOld(fID, aFile); } fi.Success(); } else { this->ReportError(fi.error, fi.message); fi.ReSignal(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void TODocCommand::Fields(TObject* obj) // override { obj->DoToField("TODocCommand", (Ptr)NULL, bClass); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TPDocCommand::IPDocCommand(CmdNumber itsCmdNumber, TList* theDocuments) { this->IFilesCommand(itsCmdNumber, theDocuments); } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal void TPDocCommand::DoIt(void) // override { FailInfo fi; if (fi.Try()) { { CObjectIterator iter(fFileList); for (TFile* aFile = (TFile*)iter.FirstObject(); iter.More(); aFile = (TFile*)iter.NextObject()) if (!gApplication->PrintDocument(aFile)) break; // guess we're done printing } fi.Success(); } else { this->ReportError(fi.error, fi.message); fi.ReSignal(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void TPDocCommand::Fields(TObject* obj) // override { obj->DoToField("TPDocCommand", (Ptr)NULL, bClass); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TAboutAppCommand::IAboutAppCommand(CmdNumber itsCmdNumber) { this->INoChangesCommand(itsCmdNumber, NULL, NULL); } //-------------------------------------------------------------------------------------------------- #pragma segment MAAboutApp pascal void TAboutAppCommand::DoIt(void) { gApplication->DoShowAboutApp(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void TAboutAppCommand::Fields(TObject* obj)// override { obj->DoToField("TAboutAppCommand", (Ptr)NULL, bClass); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TEventCommand::IEventCommand(CmdNumber itsCmdNumber) { this->INoChangesCommand(itsCmdNumber, NULL, NULL); // Hang around fFreeOnCompletion = FALSE; fRecurring = TRUE; // Let more important stuff happen first fPriority = kPriorityLow; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TEventCommand::DoIt(void) { gApplication->PollToolboxEvent(gApplication->fAllowApplicationToSleep); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void TEventCommand::Fields(TObject* obj) // override { obj->DoToField("TEventCommand", (Ptr)NULL, bClass); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #pragma segment MAInit pascal void TApplication::Initialize(void) // override { inherited::Initialize(); fAllowApplicationToSleep = TRUE; fAlwaysTrackCursor = FALSE; fAppDone = FALSE; fApplicationPSN.highLongOfPSN = kNoProcess; fApplicationPSN.lowLongOfPSN = kNoProcess; fClickCount = 0; fEventList = NULL; fCursorRgn = NULL; fDocList = NULL; fEventLevel = 1; // Prevents UnloadAllSegs from getting called // if a modal dialogs is used befure starting // the main event loop fFreeWindowList = NULL; fHeadCohandler = NULL; fHelpRgn = NULL; fIdlePhase = idleEnd; fInBackground = FALSE; // When we start an app, it's in foreground fLastClickPart = inDesk; fLastCommand = NULL; fLastMsePt = gZeroPt; fLastUpTime = TickCount(); fLaunchWithNewDocument = TRUE; fLowSpaceInterval = kLowSpaceInterval; fMainEventMask = everyEvent; fMBarDisplayed = kMBarDisplayed; fMBarNotDisplayed = kMBarNotDisplayed; fMBarHierarchical = kMBarHierarchical; fNextSpaceMsg = TickCount(); fSleepRgn = NULL; fSysWindowActive = FALSE; fTarget = this; fUndoCmd = cNoCommand; fUndoState = kShowUndo; } //-------------------------------------------------------------------------------------------------- #pragma segment MAInit pascal void TApplication::IApplication(const OSType itsMainFileType) { const Str255 kParamText1 = "^0"; short i; Str255 s; TEventList * anEventList; Str255 apName; short apRefnum; Handle apParam; TEventCommand * aEventCommand = NULL; TWindowTabber* aTabber = NULL; MenuHandle aMenu; ProcessSerialNumber aPSN; OSErr err; gApplication = this; this->IEvtHandler(NULL); fSleepRgn = MakeNewRgn(); fCursorRgn = MakeNewRgn(); fHelpRgn = MakeNewRgn(); if (qNeedsProcessMgr || gConfiguration.hasProcessMgr) { err = GetCurrentProcess(aPSN); if (err == noErr) fApplicationPSN = aPSN; } #if qInspector MakeInspector(); AddObjectToInspector(this); AddObjectToInspector(gNullPrintHandler); AddObjectToInspector(gPrintHandler); #endif fFreeWindowList = NewList(); #if qDebug fFreeWindowList->SetEltType("TWindow"); #endif fDocList = NewList(); #if qDebug fDocList->SetEltType("TDocument"); #endif // Posted commands won't go anywhere until we create the queue anEventList = new TEventList; anEventList->IEventList(); fEventList = anEventList; #if qDebug fEventList->SetEltType("TEvent"); #endif // Make the command that operates the main Event Loop aEventCommand = new TEventCommand; aEventCommand->IEventCommand(cNoCommand); this->PostCommand(aEventCommand); // Install the default tab behavior aTabber = new TWindowTabber; aTabber->ITabber(TRUE); this->AddBehavior(aTabber); fMainFileType = itsMainFileType; // !!! Do a bunch of menu setup that really should be in the menu unit or something AddMenuBar(fMBarNotDisplayed, FALSE); // reads in and initializes these menus. ClearMenuBar(); AddMenuBar(fMBarDisplayed, FALSE); AddMenuBar(fMBarHierarchical, TRUE); // Process the Apple menu aMenu = MAGetMenu(mApple); if (aMenu) AddResMenu(aMenu, 'DRVR'); // If the "About" item contains the paramtext keystring (^0) then substitute the // Application's name CmdToName(cAboutApp, s); i = s.Pos(kParamText1); if (i != 0) { GetAppParms(apName, apRefnum, apParam); s.Delete(i, kParamText1.Length()); s.Insert(apName, i); SetCmdName(cAboutApp, s); } // Add the debugger menus if (qDebug || qInspector) { AddMenuBar(kMBarDebug, FALSE); if (qDebug) { AddMenuBar(kMBarDebugHierarchical, TRUE); aMenu = MAGetMenu(mDebugFont); if (aMenu) AddResMenu(aMenu, 'FONT'); } } InvalidateMenuBar(); this->DoMakeViewServer(); // creates the view server // Finally finish up with the debugger; #if qDebug InitUDebugAfterIApplication(); #endif } //-------------------------------------------------------------------------------------------------- #pragma segment MAActivate pascal void TApplication::AboutToLoseControl(Boolean convertClipboard) { CWMgrIterator iter; this->ActivateBusyCursor(FALSE); // Don't want busy cursor while in desk acc. gClipboardMgr->AboutToLoseControl(convertClipboard); // Let all windows know that we're losing control - e.g. so floaters can hide themselves for (WindowPtr aWinPtr = iter.FirstWMgrWindow(); iter.More(); aWinPtr = iter.NextWMgrWindow()) { TWindow* aWindow = this->WMgrToWindow(aWinPtr); if (aWindow) aWindow->AboutToLoseControl(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::ActivateBusyCursor(Boolean entering) { if (gBusyCursor) gBusyCursor->Activate(entering); } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal void TApplication::AddDocument(TDocument* aNewDocument) { if (fDocList) fDocList->Insert(aNewDocument); } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal void TApplication::AddFreeWindow(TWindow* aWindow) { if (fFreeWindowList) fFreeWindowList->Insert(aWindow); } //-------------------------------------------------------------------------------------------------- #pragma segment MAGlobalsRes // Don't require a segment load for this // AlertFilter is a default filterProc used by MacAppAlert if the filterProc passed in is NULL. // It maps key strokes to the first character of button item titles. It also hands off activate // and update processing to gApplication if we're not being called from an error condition or // while nested. pascal Boolean TApplication::AlertFilter(DialogPtr theDialog, EventRecord& theEvent, short& itemHit) { static Str31 bufferString; // Must be a global, since it's used each time the // alert filter is entered. (It could be a field // of TApplication...) // If any script has a character with more than 31 // bytes then the creatures that speak that language // have too many fingers! char theChar; Rect box; short byteType; FailInfo fi; Boolean oldInFilterState = gInFilter; EventRecord anEvent; TToolboxEvent * event; Boolean returnValue = FALSE; VOLATILE(oldInFilterState); VOLATILE(returnValue); gInFilter = TRUE; if (fi.Try()) { // Wouldn't want MacApp to get lied to about where the focus _Actually_ is if (!gInhibitNestedHandling &&!oldInFilterState) this->InvalidateFocus(); switch (theEvent.what) { // this is the first event the alert gets, use it to initialize the global buffer case activateEvt: if (((DialogPtr) theEvent.message) == theDialog) bufferString = ""; // initialize bufferString else if (!gInhibitNestedHandling && !oldInFilterState) { event = new TToolboxEvent; event->IToolboxEvent(this); event->HaveEvent(theEvent); event->Process(); //!!! this->DoEvent(cNoCommand, NULL, event); } break; // this is the first event the alert gets, so let's determine our VARs case updateEvt: if (((DialogPtr) theEvent.message) != theDialog) if (!gInhibitNestedHandling &&!oldInFilterState) { event = new TToolboxEvent; event->IToolboxEvent(NULL); event->HaveEvent(theEvent); event->Process(); //!!! this->DoEvent(cNoCommand, NULL, event); } break; // let's determine if the key pressed corresponds to our button titles case keyDown: theChar = (unsigned char)(((theEvent.message) & charCodeMask)); byteType = CharByte(&theChar, 0); switch (byteType) { case smSingleByte: if ((theChar == chEnter) || (theChar == chReturn)) { DoAlertKeyDown(theDialog, ok); itemHit = ok; returnValue = TRUE; } else if ((theChar == chEscape) || ((theChar == '.') && ((theEvent.modifiers & cmdKey) != 0))) { DoAlertKeyDown(theDialog, cancel); itemHit = cancel; returnValue = TRUE; } else { bufferString += theChar; if (CompareAlertKeysToItem(theDialog, bufferString, itemHit)) { DoAlertKeyDown(theDialog, itemHit); returnValue = TRUE; } } break; case smFirstByte: bufferString += theChar; break; case smLastByte: bufferString += theChar; if (CompareAlertKeysToItem(theDialog, bufferString, itemHit)) { DoAlertKeyDown(theDialog, itemHit); returnValue = TRUE; } break; case smMiddleByte: bufferString += theChar; break; } } // Idle but only if _REALLY_ necessary if (!gInhibitNestedHandling &&!oldInFilterState &&!EventAvail(everyEvent, anEvent)) this->Idle(fIdlePhase); fi.Success(); } gInFilter = oldInFilterState; return returnValue; } //-------------------------------------------------------------------------------------------------- #pragma segment MAFile pascal TDocument* TApplication::AlreadyOpen(TFile* aFile) { CDocumentIterator iter(this); for (TDocument* aDocument = iter.FirstDocument(); iter.More(); aDocument = iter.NextDocument()) if (aDocument->AlreadyOpen(aFile)) return aDocument; return NULL; // No document already open } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::Beep(short duration) { SysBeep(duration); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFinder // This is called only when opening/printing from the finder; // it simulates the filtering done by Std File. pascal Boolean CallFileFilterWithData(HParmBlkPtr paramBlock, Ptr myDataPtr, ProcPtr routine) = { 0x205F,// MOVEA.L (A7)+,A0 0x4E90// JSR (A0) }; pascal Boolean CallFileFilter(HParmBlkPtr paramBlock, ProcPtr routine) = { 0x205F,// MOVEA.L (A7)+,A0 0x4E90// JSR (A0) }; pascal Boolean TApplication::CanOpenDocument(CmdNumber itsCmdNumber, TFile* aFile) { short dlgID; Point where; ProcPtr fileFilter; ProcPtr dlgHook; ProcPtr modalFilter; ProcPtr activateProc; Ptr activeList; Ptr yourDataPtr = NULL; TypeListHandle typeList; HParamBlockRec paramBlock; short numTypes; Boolean returnValue = FALSE; // First check that file type is in the list of allowed file types. See SFGetParms // below for more info. typeList = (TypeListHandle)NewHandle(0); FailNIL(typeList); this->SFGetParms(itsCmdNumber, fileFilter, typeList, dlgID, where, dlgHook, modalFilter, activeList, activateProc, yourDataPtr); numTypes = (short)(GetHandleSize((Handle)typeList) / sizeof(ResType)); if (numTypes == 0) { if (!fileFilter) returnValue = TRUE; // no file filter then want all types else if (aFile->GetFileInfo(paramBlock) == noErr) { if (qNeedsAliasMgr || gConfiguration.hasAliasMgr) returnValue =!CallFileFilterWithData(¶mBlock, NULL, fileFilter); else returnValue =!CallFileFilter(¶mBlock, fileFilter); } else returnValue = FALSE; } else for (short i = 1; i <= numTypes; ++i) if (((long)(aFile->fFileType)) == ((long)(**typeList)[i])) { if (!fileFilter) returnValue = TRUE; else if (aFile->GetFileInfo(paramBlock) == noErr) { if (qNeedsAliasMgr || gConfiguration.hasAliasMgr) returnValue =!CallFileFilterWithData(¶mBlock, NULL, fileFilter); else returnValue =!CallFileFilter(¶mBlock, fileFilter); } else returnValue = FALSE; break; } typeList = (TypeListHandle)DisposeIfHandle((Handle)typeList); return returnValue; } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal Boolean TApplication::ChooseApplication(AEAddressDesc& theAddress) { typedef TargetID* TargetIDPtr, ** TargetIDHandle; TargetIDHandle theTargetID; LocationNameRec theLoc; PortInfoRec thePortInfo; OSErr theErr; Str32 theLocNBPType; //!!! Boolean returnValue = FALSE; if (qNeedsAppleEventMgr || gConfiguration.hasAppleEventMgr) { theErr = PPCBrowser("", "", FALSE, theLoc, thePortInfo, NULL, ""); if (theErr == noErr) { theTargetID = (TargetIDHandle)NewHandle(sizeof(TargetID)); FailMemError(); (*theTargetID)->location = theLoc; (*theTargetID)->name = thePortInfo.name; theAddress.descriptorType = typeTargetID; theAddress.dataHandle = (Handle)theTargetID; returnValue = TRUE; } else if (theErr != userCanceledErr) FailOSErr(theErr); } return returnValue; } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal Boolean TApplication::ChooseDocument(CmdNumber itsCmdNumber, TList** aFileList) { typedef SFTypeList* SFTypeListPtr; typedef SFTypeListPtr* SFTypeListHandle; FailInfo fi; short dlgID; Point where; ProcPtr fileFilter; ProcPtr dlgHook; ProcPtr modalFilter; ProcPtr activateProc; Ptr activeList; Ptr yourDataPtr = NULL; TypeListHandle typeList; SFTypeListPtr pTypeList; short numTypes; StandardFileReply customReply; SFReply reply; TFile * aFile = NULL; Boolean fileChosen; VOLATILE(aFileList); VOLATILE(aFile); typeList = (TypeListHandle)NewHandle(0); FailNIL(typeList); this->SFGetParms(itsCmdNumber, fileFilter, typeList, dlgID, where, dlgHook, modalFilter, activeList, activateProc, yourDataPtr); numTypes = (short)(GetHandleSize((Handle) typeList) / sizeof(ResType)); if (numTypes == 0) { numTypes = -1; // Tell Std File to display all types. pTypeList = (SFTypeListPtr) & pTypeList;// arbitrary, as long as it points to 4 bytes of valid memory } else { LockHandleHigh((Handle)typeList); // in case Std File does allocations pTypeList = *((SFTypeListHandle)typeList); } #if qDebug // Causes TApplication.GetEvent to call CheckRsrcUsage. gRsrcCheck = 0; #endif this->UpdateAllWindows(); // needed to work around bug in SF; if all // windows are not updated you wont be able // to mount a disk correctly. ??? is this still true? if (fi.Try()) { aFile = this->DoMakeFile(itsCmdNumber); fileChosen = FALSE; if (qNeedsAliasMgr || gConfiguration.hasAliasMgr) { CustomGetFile((FileFilterYDProcPtr)fileFilter, numTypes, (*pTypeList), customReply, dlgID, where, (DlgHookYDProcPtr)dlgHook, (ModalFilterYDProcPtr)modalFilter, (short*)activeList, (ActivateYDProcPtr)activateProc, yourDataPtr); fileChosen = customReply.sfGood; if (fileChosen) { aFile->IdentifyWithScript(customReply.sfFile, customReply.sfScript); aFile->fFileType = customReply.sfType;// Mouser needs the file type! } } else { SFPGetFile(where, "", (FileFilterProcPtr)fileFilter, numTypes, (*pTypeList), (DlgHookProcPtr)dlgHook, reply, dlgID, (ModalFilterProcPtr)modalFilter); fileChosen = reply.good; if (fileChosen) { FailOSErr(aFile->IdentifyByTrio(reply.vRefNum, 0, reply.fName)); aFile->fFileType = reply.fType; // Remember the file type } } fi.Success(); } else // Recover { *aFileList = (TList *)FreeIfObject(*aFileList); aFile = (TFile *)FreeIfObject(aFile); fi.ReSignal(); } typeList = (TypeListHandle)DisposeIfHandle((Handle)typeList); if (fileChosen) { // Return the file(s) chosen *aFileList = NewList(); (*aFileList)->InsertLast(aFile); // !!! Eventually we need to return more than one file } else // user cancelled or something aFile = (TFile *)(FreeIfObject(aFile)); // free the unwanted file object return fileChosen; } //-------------------------------------------------------------------------------------------------- #pragma segment MATerminate pascal void TApplication::Close(void) { // Close all of the visible non-floater windows WindowPtr aWMgrWindow; while(aWMgrWindow = MAFrontWindow()) this->CloseWMgrWindow(aWMgrWindow); // Close all of the windows while(aWMgrWindow = FrontWindow()) this->CloseWMgrWindow(aWMgrWindow); // Close any windowless documents. Add a block for failure handling { CDocumentIterator iter(this); for (TDocument* aDocument = iter.FirstDocument(); iter.More(); aDocument = iter.NextDocument()) aDocument->Close(); } //??? gPrintHandler->Terminate(); // Close down the cohandler chain. Add a block for failure handling { CHandlerIterator iter(fHeadCohandler); for (TEvtHandler* aHandler = iter.FirstHandler(); iter.More(); aHandler = iter.NextHandler()) FreeIfObject(aHandler); // ??? also call Terminate ??? } gClipboardMgr->Close(); gViewServer->Free(); // won't be creating any more views... } //-------------------------------------------------------------------------------------------------- #pragma segment MAClose pascal void TApplication::CloseWMgrWindow(WindowPtr aWMgrWindow) { TWindow * aWindow; if (qNeedsProcessMgr || gConfiguration.hasProcessMgr ||!IsDeskAccessory(aWMgrWindow)) { aWindow = this->WMgrToWindow(aWMgrWindow); if (aWindow) aWindow->CloseByUser(); else HideWindow(aWMgrWindow); } else CloseDeskAcc(((WindowPeek)aWMgrWindow)->windowKind); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::CommitLastCommand(void) { gClipboardMgr->AbandonUndoClipboard(); if (fLastCommand) { if (fLastCommand->fCmdDone) fLastCommand->Commit(); if (fLastCommand->ShouldFreeOnCompletion()) fLastCommand = (TCommand *)(FreeIfObject(fLastCommand)); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal short TApplication::CountClicks(TToolboxEvent* event, short whereMouseDown) { short newClickCount; newClickCount = 1; if ((whereMouseDown == fLastClickPart) && // clicked in the same place… (fClickCount > 0) && // not the first click… (event->fEventRecord.when - fLastUpTime < GetDblTime()) &&// close enough in time… this->GetTarget()->DoMultiClick(fLastMsePt, event->fEventRecord.where))// close enough in space newClickCount = fClickCount + 1; fLastMsePt = event->fEventRecord.where; fLastClickPart = whereMouseDown; fClickCount = newClickCount; return newClickCount; } //-------------------------------------------------------------------------------------------------- #pragma segment MAClose pascal void TApplication::DeleteDocument(TDocument* docToDelete) { if (fDocList) fDocList->Delete(docToDelete); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::DeleteFreeWindow(TWindow* windowToDelete) { if (fFreeWindowList) fFreeWindowList->Delete(windowToDelete); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::DispatchEvent(TEvent* event) { TToolboxEvent * aToolboxEvent; //For Toolbox events, fID == fEventRecord.what if ((event) && event->IsMemberClass(GetClassIDFromName("TToolboxEvent"))) { aToolboxEvent = (TToolboxEvent *)event; switch (aToolboxEvent->fID) { case mouseUp: this->HandleMouseUp(aToolboxEvent); break; case mouseDown: this->HandleMouseDown(aToolboxEvent); break; case activateEvt: this->HandleActivateEvent(aToolboxEvent); break; case updateEvt: this->HandleUpdateEvent(aToolboxEvent); break; case keyDown: case autoKey: this->HandleKeyDownEvent(aToolboxEvent); break; case keyUp: // !!! We'd like to have a chain for keyUp but a MultiFinder™ bug // at least up to 6.0) keep us from reliably getting keyUp events // after minor context switches (background updates, etc.). It replaces // the global event mask (which we would have had to change to get keyups // in the first place) with the wrong mask. Oh well, we had such good intentions! break; case diskEvt: this->HandleDiskEvent(aToolboxEvent); break; case osEvt: this->HandleSystemEvent(aToolboxEvent); break; case nullEvent: case networkEvt: case driverEvt: case app1Evt: case app2Evt: case app3Evt: this->HandleAlienEvent(event); break; case kHighLevelEvent: this->HandleHighLevelEvent(aToolboxEvent); break; default: this->HandleAlienEvent(event); break; } } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal OSErr TApplication::DispatchAppleEvent(const AppleEvent& message, const AppleEvent& reply, long info) { FailInfo fi; OSErr theErr = noErr; // Wrap this in a failure handler so that if some failure should occur (out of memory, etc.) // we are sure to inform the AppleEvent manager. This will also inform the AppleEvent // manager if the event was not handled. However, if the event is handled by posting a // command, any errors that occur while processing the command will be handled by a] // special failure handler in TAppleCommand::Process(). if (fi.Try()) { this->GetTarget()->HandleAppleCommand(info, message, reply); fi.Success(); } else theErr = fi.error; return theErr; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::DoAppleCommand(CmdNumber aCmdNumber, const AppleEvent& message, const AppleEvent& reply) { TODocCommand * anODocCommand = NULL; TPDocCommand * aPDocCommand = NULL; switch (aCmdNumber) { case cFinderNew: // Special case the old MacPaint™ style open if user knows about the option key. // !!! Probably should be changed to check the user interaction level first, though. if (IsOptionKeyDown()) this->HandleMenuCommand(cOpen); else if (fLaunchWithNewDocument) this->GetTarget()->HandleMenuCommand(cFinderNew); break; case cFinderOpen: anODocCommand = new TODocCommand; anODocCommand->InitFromAppleEvent(aCmdNumber, NULL, NULL, message, reply); this->PostCommand(anODocCommand); break; case cFinderPrint: aPDocCommand = new TPDocCommand; aPDocCommand->InitFromAppleEvent(aCmdNumber, NULL, NULL, message, reply); this->PostCommand(aPDocCommand); break; case cFinderQuit: this->GetTarget()->HandleMenuCommand(cQuit); break; default: inherited::DoAppleCommand(aCmdNumber, message, reply); break; } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::DoCommandKey(TToolboxEvent* event)// override { if ((!event->fAutoKey) && (!InModalMenuState())) { this->SetupTheMenus(); // If you want to have case sensitive command keys use the following line because // KeyEventToComponents returns the correct character for shifted keys when the command // key is down. That lets us test for things like command-period correctly. So… in order // to be backward compatible (sigh) we now have to ignore the _correct_ char that is passed // in (and is in event->fCharacter) and use the old ToolBox supplied unPasteurized character that // is left in the actual EventRecord // this->MenuEvent(MenuKey(event->fCharacter)); this->MenuEvent(MenuKey((unsigned char)(((event->fEventRecord.message) & charCodeMask)))); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::DoKeyCommand(TToolboxEvent* event)// override { switch (event->fKeyCode) { case kF1VirtualCode: this->SetupTheMenus(); if (CmdEnabled(cUndo)) this->GetTarget()->HandleMenuCommand(cUndo); break; case kF2VirtualCode: this->SetupTheMenus(); if (CmdEnabled(cCut)) this->GetTarget()->HandleMenuCommand(cCut); break; case kF3VirtualCode: this->SetupTheMenus(); if (CmdEnabled(cCopy)) this->GetTarget()->HandleMenuCommand(cCopy); break; case kF4VirtualCode: this->SetupTheMenus(); if (CmdEnabled(cPaste)) this->GetTarget()->HandleMenuCommand(cPaste); break; case kClearVirtualCode: this->SetupTheMenus(); if (CmdEnabled(cClear)) this->GetTarget()->HandleMenuCommand(cClear); break; default: inherited::DoKeyCommand(event); break; } } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal TDocument* TApplication::DoMakeDocument(CmdNumber, TFile* itsFile) /* E X A M P L E { TDocument* aYOURDocument; aYOURDocument = new TDocument; aYOURDocument->IYOURDocument(); return aYOURDocument; } */ { TFileBasedDocument * aDocument; // Allocate and initialize the document aDocument = NULL; if (qTemplateViews) aDocument = (TFileBasedDocument *)(NewStdObject(kStdDocument)); else aDocument = new TFileBasedDocument; aDocument->IFileBasedDocument(itsFile, fMainFileType, '????', '????', kUsesDataFork, kUsesRsrcFork, !kDataOpen, !kRsrcOpen); return aDocument; } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal TFile* TApplication::DoMakeFile(CmdNumber) { return NewFile(); } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TApplication::DoMenuCommand(CmdNumber aCmdNumber) { FailInfo fi; TWindow * aWindow; TNewDocCommand * aNewDocCommand; TODocCommand * anODocCommand; TList * aFileList = NULL; TAboutAppCommand * aAboutAppCommand; TQuitCommand * aQuitCommand; TUndoRedoCommand * aUndoRedoCommand; Boolean oldObjectPerm; VOLATILE(aFileList); #if qDebug TDebugCommand * aDebugCommand; Boolean oldState; #endif #if qInspector TInspectorCommand * aInspectorCommand; Boolean oldIState; #endif /* ================================================================================== Some commands will be posted to perform actions that must _ALWAYS_ be available. The allocation cannot be allowed to fail. So we do a temp allocation which by definition cannot be allowed to fail. This strategy is used wherever we want to use command objects but don't want to leave the user twisting in the breeze. NOTE: Don't forget to allow for this memory in your mem! resource if you copy this style in your own code. ================================================================================== */ aWindow = this->GetActiveWindow(); switch (aCmdNumber) { case cQuit: oldObjectPerm = AllocateObjectsFromPerm(FALSE); aQuitCommand = new TQuitCommand; AllocateObjectsFromPerm(oldObjectPerm); aQuitCommand->IQuitCommand(aCmdNumber); this->PostCommand(aQuitCommand); break; case cNew: // cNew..cNewLast: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case cNewLast: case cFinderNew: aNewDocCommand = new TNewDocCommand; aNewDocCommand->INewDocCommand(aCmdNumber); this->PostCommand(aNewDocCommand); break; case cOpen: // cOpen..cOpenLast: case 21: case 22: case 23: case 24: case 25: case 26: case 27: case 28: case cOpenLast: if (this->ChooseDocument(aCmdNumber, &aFileList)) { if (fi.Try()) { anODocCommand = new TODocCommand; anODocCommand->IODocCommand(aCmdNumber, aFileList); fi.Success(); } else // Recover { aFileList = (TList *)(FreeIfObject(aFileList)); fi.ReSignal(); } this->PostCommand(anODocCommand); } break; case cClose: if (qDebug && this->WMgrToWindow(FrontWindow())) ProgramBreak("The frontmost window is a window object but didn''t handle the cClose CmdNumber, your TWindow subclass probably forgot to call inherited::DoMenuCommand!"); this->CloseWMgrWindow(FrontWindow()); // TWindow would have handled the command // before we get here so the window is break; // probably a DA or something case cAboutApp: aAboutAppCommand = new TAboutAppCommand; aAboutAppCommand->IAboutAppCommand(aCmdNumber); this->PostCommand(aAboutAppCommand); break; #if qDebug case cDebugWind: DebugShowTranscriptWindow(); break; case cExperimenting: gExperimenting =!gExperimenting; break; case cReportEvt: gReportEvt =!gReportEvt; break; case cDebugPrinting: gDebugPrinting =!gDebugPrinting; break; case cReportMenuChoices: gReportMenuChoices =!gReportMenuChoices; break; case cIntenseDebugging: gIntenseDebugging =!gIntenseDebugging; break; case cRefreshFrontWindow: if (aWindow) aWindow->ForceRedraw(); break; case cModalToggle: if (aWindow) aWindow->fIsModal =!aWindow->fIsModal; break; case cDoFirstClick: if (aWindow) aWindow->fDoFirstClick =!aWindow->fDoFirstClick; break; case cSetSysJust: // swap the current setting if (GetActualJustification(teFlushDefault) == teFlushLeft) SetSysJust(teFlushRight); else SetSysJust(teFlushLeft); break; case cEnterMacAppDebugger: oldObjectPerm = AllocateObjectsFromPerm(FALSE); oldState = AddNewObjectsToInspector(FALSE); aDebugCommand = new TDebugCommand; AddNewObjectsToInspector(oldState); AllocateObjectsFromPerm(oldObjectPerm); aDebugCommand->IDebugCommand(aCmdNumber); this->PostCommand(aDebugCommand); break; #endif #if qDebug case cTraceSetupMenus: gTraceSetupMenus =!gTraceSetupMenus; break; case cTraceIdle: gTraceIdle =!gTraceIdle; break; #endif #if qInspector case cNewInspectorWindow: oldIState = AddNewObjectsToInspector(FALSE); aInspectorCommand = new TInspectorCommand; AddNewObjectsToInspector(oldIState); aInspectorCommand->IInspectorCommand(aCmdNumber); this->PostCommand(aInspectorCommand); break; #endif case cUndo: oldObjectPerm = AllocateObjectsFromPerm(FALSE); aUndoRedoCommand = new TUndoRedoCommand; AllocateObjectsFromPerm(oldObjectPerm); aUndoRedoCommand->IUndoRedoCommand(aCmdNumber); this->PostCommand(aUndoRedoCommand); break; default: inherited::DoMenuCommand(aCmdNumber); break; } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::DoSetupMenus(void) { Boolean lowSpace; WindowPtr aWindowPtr; inherited::DoSetupMenus(); lowSpace = MemSpaceIsLow(); Enable(cAboutApp, TRUE); Enable(cQuit, fEventLevel <= 1); // Can't enable Quit if in nested event handling Enable(cNew, !lowSpace); Enable(cOpen, !lowSpace); aWindowPtr = FrontWindow(); if ((aWindowPtr) && (this->WMgrToWindow(aWindowPtr) == NULL)) // window objects will take care of themselves, but we take care of the indigent. Enable(cClose, ((WindowPeek)aWindowPtr)->goAwayFlag != FALSE); } //-------------------------------------------------------------------------------------------------- #pragma segment MAAboutApp Boolean hadCreditsStringList; // does the rsrc 'STR#' == kDefaultCredits exist ? short lastCreditsStringIndex; // the last string in the STR# to be displayed long lastCreditsShownTicks; // the tickcount when the last Credit was Shown StringHandle originalText; // the about box's original text (prior to credits) short waitTicks; // how long to wait between credits pascal Boolean DoShowAboutAppFilter(DialogPtr theDialog, EventRecord& theEvent, short& itemHit) { Str255 s; Str255 originalStr; Handle item; Boolean returnValue = FALSE; short itemType; Rect box; switch (theEvent.what) { case keyDown: switch ((unsigned char)(((theEvent.message) & charCodeMask))) { case chEnter: case chReturn: DoAlertKeyDown(theDialog, ok); break; } break; case nullEvent: if ((TickCount() - lastCreditsShownTicks) > waitTicks) { short itemNo = 1; do { item = NULL; GetDItem(theDialog, itemNo, itemType, item, box); if (((itemType) & 0x7F) == statText) // we don't care if its enabled or not break; else ++itemNo; } while (item); GetIndString(s, kDefaultCredits, lastCreditsStringIndex); if (!s.IsEmpty()) { // save the original text if ((lastCreditsStringIndex == 1) && ((*originalText)->IsEmpty() && item)) { GetIText(item, originalStr); SetString(originalText, originalStr); } ++lastCreditsStringIndex; lastCreditsShownTicks = TickCount(); if (item) SetIText(item, s); waitTicks = (short)Min((s.Length() * 6), 60); } else // no more items { lastCreditsStringIndex = 1; lastCreditsShownTicks = TickCount(); if (item) { BlockMove(((Ptr) *originalText), (Ptr) & originalStr, (**originalText).Length() + 1); SetIText(item, originalStr); } waitTicks = 6 * 60; } } break; } /* switch */ // Forward on to the standard filter if (gMacAppAlertFilter) returnValue = CallAlertFilter(theDialog, theEvent, itemHit, gMacAppAlertFilter); return returnValue; } //-------------------------------------------------------------------------------------------------- #pragma segment MAAboutApp pascal void TApplication::DoShowAboutApp(void) /* Method to display the "About" box for your application. Override to do interesting things. Since it is normally called from a command; the app usually has the maximum free space available. */ { Str255 apName; short apRefnum; Handle apParam; FailSpaceIsLow(); GetAppParms(apName, apRefnum, apParam); ParamText(apName, "", "", ""); // Put Application name in the about box hadCreditsStringList = (GetResource('STR#', kDefaultCredits) != NULL); if (hadCreditsStringList) { lastCreditsStringIndex = 1; lastCreditsShownTicks = TickCount(); waitTicks = 5 * 60; originalText = NewString(""); MacAppAlert(phAboutApp, (ProcPtr) & DoShowAboutAppFilter); originalText = (StringHandle)DisposeIfHandle((Handle)originalText); } else StdAlert(phAboutApp); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::EachActiveWindow(DoToWindowType DoToWindow, void* staticLink) { if ((qNeedsProcessMgr) || (gConfiguration.hasProcessMgr) || (!IsDeskAccessory(FrontWindow()))) { CWMgrIterator iter; for (WindowPtr aWinPtr = iter.FirstWMgrWindow(); iter.More(); aWinPtr = iter.NextWMgrWindow()) { TWindow* aWindow = this->WMgrToWindow(aWinPtr); if ((aWindow) && (aWindow->IsShown()) && (aWindow->IsActive())) DoToWindow(aWindow, staticLink); } } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::EachFreeWindow(pascal void(* DoToWindow)(TWindow* aWindow, void* staticLink), void* staticLink) { if (fFreeWindowList) fFreeWindowList->Each((DoToObjectType)DoToWindow, staticLink); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFields pascal void DoGlobalFields(TObject* obj) { obj->DoToField("gApplication", &gApplication, bObject); obj->DoToField("gApplicationStyle", &gApplicationStyle, bTextStyle); obj->DoToField("gConfiguration", &gConfiguration, bConfigRec); obj->DoToField("gCouldPrint", &gCouldPrint, bBoolean); obj->DoToField("gCurrPrintHandler", &gCurrPrintHandler, bObject); obj->DoToField("gDrawingPictScrap", &gDrawingPictScrap, bBoolean); obj->DoToField("gDrawingPictScrapView", &gDrawingPictScrapView, bObject); obj->DoToField("gErrorParm3", &gErrorParm3, bString); obj->DoToField("gFocusedView", &gFocusedView, bObject); obj->DoToField("gInitialized", &gInitialized, bBoolean); obj->DoToField("gMenuBarIsInvalid", &gMenuBarIsInvalid, bBoolean); obj->DoToField("gMenusAreInvalid", &gMenusAreInvalid, bBoolean); obj->DoToField("gNullPrintHandler", &gNullPrintHandler, bObject); obj->DoToField("gNumUntitled", &gNumUntitled, bInteger); obj->DoToField("gOldChooserFlag", &gOldChooserFlag, bBoolean); obj->DoToField("gOrthogonal[hSel]", &gOrthogonal[hSel], bByte); obj->DoToField("gOrthogonal[vSel]", &gOrthogonal[vSel], bByte); obj->DoToField("gPageOffset", &gPageOffset, bVPoint); obj->DoToField("gPrintHandler", &gPrintHandler, bObject); obj->DoToField("gPrinting", &gPrinting, bBoolean); obj->DoToField("gStdHysteresis", &gStdHysteresis, bPoint); obj->DoToField("gStdStaggerCount", &gStdStaggerCount, bInteger); obj->DoToField("gStdWMoveBounds", &gStdWMoveBounds, bRect); obj->DoToField("gStdWScreenRect", &gStdWScreenRect, bRect); obj->DoToField("gStdWSizeRect", &gStdWSizeRect, bRect); obj->DoToField("gSystemStyle", &gSystemStyle, bTextStyle); obj->DoToField("gTempRgn", &gTempRgn, bRgnHandle); obj->DoToField("gWorkPort", &gWorkPort, bGrafPtr); obj->DoToField("gWResSignature", &gWResSignature, bIDType); obj->DoToField("gWResType", &gWResType, bString); obj->DoToField("gZeroPt", &gZeroPt, bPoint); obj->DoToField("gZeroRect", &gZeroRect, bRect); obj->DoToField("gZeroVPt", &gZeroVPt, bVPoint); obj->DoToField("gZeroVRect", &gZeroVRect, bVRect); #if qDebug obj->DoToField("gBusyTempRgn", &gBusyTempRgn, bBoolean); obj->DoToField("gDebugPrinting", &gDebugPrinting, bBoolean); obj->DoToField("gExperimenting", &gExperimenting, bBoolean); obj->DoToField("gIntenseDebugging", &gIntenseDebugging, bBoolean); obj->DoToField("gReportEvt", &gReportEvt, bBoolean); obj->DoToField("gReportMenuChoices", &gReportMenuChoices, bBoolean); obj->DoToField("gRsrcCheck", &gRsrcCheck, bBoolean); obj->DoToField("gTraceIdle", &gTraceIdle, bBoolean); obj->DoToField("gUsedBy", &gUsedBy, bString); #endif } pascal void TApplication::Fields(TObject* obj) // override { obj->DoToField("TApplication", (Ptr)NULL, bClass); obj->DoToField("fAppDone", &fAppDone, bBoolean); obj->DoToField("fApplicationPSN.highLongOfPSN", &fApplicationPSN.highLongOfPSN, bLongInt); obj->DoToField("fApplicationPSN.lowLongOfPSN", &fApplicationPSN.lowLongOfPSN, bLongInt); obj->DoToField("fClickCount", &fClickCount, bInteger); obj->DoToField("fEventList", &fEventList, bObject); obj->DoToField("fCursorRgn", &fCursorRgn, bRgnHandle); obj->DoToField("fDocList", &fDocList, bObject); obj->DoToField("fEventLevel", &fEventLevel, bInteger); obj->DoToField("fFreeWindowList", &fFreeWindowList, bObject); obj->DoToField("fHeadCohandler", &fHeadCohandler, bObject); obj->DoToField("fHelpRgn", &fHelpRgn, bRgnHandle); obj->DoToField("fIdlePhase", &fIdlePhase, bByte); obj->DoToField("fInBackground", &fInBackground, bBoolean); obj->DoToField("fLastClickPart", &fLastClickPart, bInteger); obj->DoToField("fLastCommand", &fLastCommand, bObject); obj->DoToField("fLastMsePt", &fLastMsePt, bPoint); obj->DoToField("fLastUpTime", &fLastUpTime, bLongInt); obj->DoToField("fLaunchWithNewDocument", &fLaunchWithNewDocument, bBoolean); obj->DoToField("fLowSpaceInterval", &fLowSpaceInterval, bLongInt); obj->DoToField("fMainEventMask", &fMainEventMask, bHexInteger); obj->DoToField("fMainFileType", &fMainFileType, bOSType); obj->DoToField("fMBarDisplayed", &fMBarDisplayed, bInteger); obj->DoToField("fMBarHierarchical", &fMBarHierarchical, bInteger); obj->DoToField("fMBarNotDisplayed", &fMBarNotDisplayed, bInteger); obj->DoToField("fNextSpaceMsg", &fNextSpaceMsg, bLongInt); obj->DoToField("fSleepRgn", &fSleepRgn, bRgnHandle); obj->DoToField("fSysWindowActive", &fSysWindowActive, bBoolean); obj->DoToField("fTarget", &fTarget, bObject); obj->DoToField("fUndoCmd", &fUndoCmd, bInteger); obj->DoToField("fUndoState", &fUndoState, bBoolean); DoGlobalFields(obj); inherited::Fields(obj); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::ForAllDocumentsDo(pascal void(* DoToDoc)(TDocument* aDocument, void* staticLink), void* staticLink) { if (fDocList) fDocList->Each((DoToObjectType)DoToDoc, staticLink); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::ForAllWindowsDo(DoToWindowType DoToWindow, void* staticLink) { CDocumentIterator iter(this); for (TDocument* aDocument = iter.FirstDocument(); iter.More(); aDocument = iter.NextDocument()) aDocument->ForAllWindowsDo(DoToWindow, staticLink); this->EachFreeWindow(DoToWindow, staticLink); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::ExcludeWindowRegions(RgnHandle deskTopRgn, TestWindowType TestWindow, void* staticLink) { GrafPtr savedPort; CWMgrIterator iter; // Remove the visRgn of all windows for which TestWindow returns TRUE GetPort(savedPort); for (WindowPtr aWinPtr = iter.FirstWMgrWindow(); iter.More(); aWinPtr = iter.NextWMgrWindow()) { TWindow* aWindow = this->WMgrToWindow(aWinPtr); if (aWindow && TestWindow(aWindow, staticLink)) { // Convert the visRgn to global coordinates //###SRF SetPort(aWinPtr); aWindow->LocalToSuperRgn(aWinPtr->visRgn); // Remove the visRgn from the cursor region DiffRgn(deskTopRgn, aWinPtr->visRgn, deskTopRgn); // Convert the visRgn back to local (port) coordinates aWindow->SuperToLocalRgn(aWinPtr->visRgn); } } SetPort(savedPort); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal Boolean WindowHandlesCursor(TWindow* aWindow, void*) { return ((aWindow->IsShown()) && (aWindow->HandlesCursor())); } // Make the region the desktop less the active window, and any first click windows. // The current mouse location is added. pascal void TApplication::GetDefaultCursorRgn(Point/* globalMouse */, RgnHandle cursorRgn) { // Start off with the "desktop region" GetDeskTopRegion(cursorRgn); // Remove the visRgn of all windows which claim the cursor this->ExcludeWindowRegions(cursorRgn, WindowHandlesCursor, this); // make sure mouse's current location is included //!!!RCR Done in TrackCursor. PtAndRgn(globalMouse, cursorRgn); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal Boolean WindowHandlesHelp(TWindow* aWindow, void*) { return ((aWindow->IsShown()) && (aWindow->HandlesHelp())); } // Make the region the desktop less the active window, and any first click windows. // The current mouse location is added. pascal void TApplication::GetDefaultHelpRgn(Point /* globalMouse */, RgnHandle helpRgn) { // Start off with the "desktop region" GetDeskTopRegion(helpRgn); // Remove the visRgn of all windows which handle help this->ExcludeWindowRegions(helpRgn, WindowHandlesHelp, this); // make sure mouse's current location is included //!!!RCR Done in TrackCursor. PtAndRgn(globalMouse, helpRgn); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal RgnHandle TApplication::GetSleepRgn(void) { Point globalMouse; Boolean isSleepInvalid; if (this->IsFrontProcess()) { // Compute based on where the mouse is right NOW GetMouse(globalMouse); LocalToGlobal(globalMouse); isSleepInvalid = FALSE; // The help region is computed before the cursor rgn so that // the cursor region excludes the balloon shape if ((this->IsHelpRgnInvalid()) && (this->IsHelpEnabled())) { this->TrackHelp(globalMouse); isSleepInvalid = TRUE; } if (this->IsCursorRgnInvalid()) { this->TrackCursor(globalMouse); isSleepInvalid = TRUE; } if (isSleepInvalid) if (this->IsHelpEnabled()) SectRgn(fCursorRgn, fHelpRgn, fSleepRgn); else CopyRgn(fCursorRgn, fSleepRgn); // Ensure that the sleep region contains the mouse. PtAndRgn(globalMouse, fSleepRgn); return fSleepRgn; } else return NULL; } //-------------------------------------------------------------------------------------------------- #pragma segment MAInspector pascal void TApplication::GetInspectorName(Str255& inspectorName) { if (this == gApplication) inspectorName = "gApplication"; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal TToolboxEvent* TApplication::GetEvent(short eventMask, long sleep, RgnHandle sleepRgn) { const short osMask = app4Mask; // One wonders when this will be in the interfaces #if qPerform Boolean oldSetting; #endif #if qDebug CGrafPort desktopPort; // Used for showing cursor region long ticks; // Used for showing cursor region GrafPtr savedPort; // Used for showing cursor region #endif EventRecord anEvent; TToolboxEvent * aTEvent; TToolboxEvent * returnValue; #if qDebug --gRsrcCheck; if (gRsrcCheck <= 0) { CheckRsrcUsage(); gRsrcCheck = kRsrcCheckInterval; } #endif if (gIntenseDebugging && gReportEvt) { fprintf(stderr, "WaitNextEvent: sleep=0%d", sleep); // faceless driver bug fixed in MF 7.0 if (sleepRgn == NULL) fprintf(stderr, ", sleep region=NULL"); else WrLblRect(", sleep region", (*sleepRgn)->rgnBBox); fprintf(stderr, "\n"); } #if qDebug if (gShowCursorRegion || gShowHelpRegion || gShowSleepRegion) { // Cursor region is in global coords. Need to create desktop port GetPort(savedPort); if (qNeedsColorQD || gConfiguration.hasColorQD) OpenCPort(&desktopPort); else OpenPort((GrafPtr) & desktopPort); CopyRgn(GetGrayRgn(), desktopPort.visRgn); desktopPort.portRect = (*(desktopPort.visRgn))->rgnBBox; PenNormal(); PenMode(patXor); if (gShowCursorRegion) { PaintRgn(fCursorRgn); Delay(30, ticks); PaintRgn(fCursorRgn); } if (gShowHelpRegion) { PaintRgn(fHelpRgn); Delay(30, ticks); PaintRgn(fHelpRgn); } if (gShowSleepRegion) { PaintRgn(fSleepRgn); Delay(30, ticks); PaintRgn(fSleepRgn); } sleep = 60; if (qNeedsColorQD || gConfiguration.hasColorQD) CloseCPort(&desktopPort); else ClosePort((GrafPtr) & desktopPort); SetPort(savedPort); } #endif this->ActivateBusyCursor(FALSE); // Turn off busy cursor while we're away. #if qPerform oldSetting = DebugPerfMonitor(FALSE); #endif // SystemEvents aren't queued and will be lost if not retrieved when available. So we // ensure here that they are always retrieved by adding osMask. if (WaitNextEvent(((eventMask) | osMask), anEvent, sleep, sleepRgn)) { aTEvent = new TToolboxEvent; // ###!!!SRF use a cacheing system aTEvent->IToolboxEvent(this); aTEvent->HaveEvent(anEvent); returnValue = aTEvent; } else returnValue = NULL; #if qPerform DebugPerfMonitor(oldSetting); #endif if (this->IsFrontProcess()) // If we're not in the background, then this->ActivateBusyCursor(TRUE); // …enable the busy cursor mechanism. return returnValue; } //-------------------------------------------------------------------------------------------------- #pragma segment MAUtilitiesRes pascal void EachWMgrWindowDoTill(pascal Boolean(* DoToWMgrWindow)(WindowPtr theWMgrWindow, void* staticLink), void* staticLink) { CWMgrIterator iter; for (WindowPtr aWindowPtr = iter.FirstWMgrWindow(); iter.More(); aWindowPtr = iter.NextWMgrWindow()) if (!DoToWMgrWindow(aWindowPtr, staticLink)) break; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal TWindow* TApplication::GetFrontWindow(void) { if (qNeedsProcessMgr || gConfiguration.hasProcessMgr ||!IsDeskAccessory(FrontWindow())) { CWMgrIterator iter; for (WindowPtr aWinPtr = iter.FirstWMgrWindow(); iter.More(); aWinPtr = iter.NextWMgrWindow()) { TWindow* aWindow = this->WMgrToWindow(aWinPtr); if ((aWindow) && (aWindow->IsShown()) && (!aWindow->fFloats)) return aWindow; } } return NULL; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal TWindow* TApplication::GetActiveWindow(void) { if (qNeedsProcessMgr || gConfiguration.hasProcessMgr ||!IsDeskAccessory(FrontWindow())) { CWMgrIterator iter; for (WindowPtr aWinPtr = iter.FirstWMgrWindow(); iter.More(); aWinPtr = iter.NextWMgrWindow()) { TWindow* aWindow = this->WMgrToWindow(aWinPtr); if ((aWindow) && (aWindow->IsShown()) && (aWindow->IsActive()) && (!aWindow->fFloats)) return aWindow; } } return NULL; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal TCommand* TApplication::GetLastCommand(void) { return fLastCommand; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal TEvent* TApplication::RetrieveAnEvent(void) { TEvent * anEvent; if (!fEventList->IsEmpty()) { // Higher priority events are at the end of the list. CObjectIterator iter(fEventList, kIterateBackward); for (TEvent* itsEvent = (TEvent*)iter.FirstObject(); iter.More(); itsEvent = (TEvent*)iter.NextObject()) { if (itsEvent->IsReadyToExecute()) { anEvent = itsEvent; break; } } if ((anEvent) && !anEvent->IsRecurring()) fEventList->Delete(anEvent); return anEvent; } else return NULL; } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen // ??? We should not muck with the window template; the extra code isn't worth it since // programmer can easily change the resource file ??? pascal WindowPtr TApplication::GetRsrcWindow(Ptr storage, short rsrcId, Boolean& isResizable, Boolean& isClosable) // We force INVISIBLE in the WIND definition so the screen won't flash. { struct WINDTemplate { Rect bounds; short procID; Boolean visible, filler1; Boolean goAway, filler2; long refcon; short itemsID; // only for DLOG resource }; typedef WINDTemplate* WINDTemplatePtr, ** WINDTemplateHandle; WindowPtr aWMgrWindow; WINDTemplateHandle templateHandle; Boolean oldPerm; FailInfo fi; VOLATILE(oldPerm); // Even though the window is permanent, we allocate it under a temporary flag so that the // maximum memory is available. Quickdraw can blow up if it can't allocate a grafPort. oldPerm = PermAllocation(FALSE); if (fi.Try()) { templateHandle = (WINDTemplateHandle) GetResource('WIND', rsrcId); FailNILResource((Handle)templateHandle); MoveHHi((Handle)templateHandle); // in case it is locked by the ROM WINDTemplate& templateData = **templateHandle; templateData.visible = FALSE; isClosable = templateData.goAway; isResizable = ((templateData.procID == documentProc) || (templateData.procID == zoomDocProc)); // If your own defProc is resizable, too, then after the call on GetRsrcWindow, set // isResizable TRUE if (qNeedsColorQD || gConfiguration.hasColorQD) aWMgrWindow = (WindowPtr)(GetNewCWindow(rsrcId, (Ptr)(storage), (WindowPtr)(-1))); else aWMgrWindow = GetNewWindow(rsrcId, (Ptr)(storage), (WindowPtr)(-1)); FailNIL(aWMgrWindow); oldPerm = PermAllocation(oldPerm); fi.Success(); } else // Recover. Don't need the failure handler since we've set the perm allocation flag back. { // Make sure the perm allocation flag is set back to what it was // when we entered GetRsrcWindow. oldPerm = PermAllocation(oldPerm); fi.ReSignal(); } // Now we must make sure that the code reserve is still intact. if (!CheckReserve()) { aWMgrWindow = FreeIfWMgrWindow(aWMgrWindow, storage == NULL); Failure(memFullErr, 0); } return aWMgrWindow; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal TEvtHandler* TApplication::GetTarget(void) { return fTarget; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::HandleActivateEvent(TToolboxEvent* event) { TWindow * aWindow; aWindow = this->WMgrToWindow((WindowPtr)(event->fEventRecord.message)); if (aWindow) aWindow->Activate(((event->fEventRecord.modifiers) & activeFlag) != 0); else this->HandleAlienEvent(event); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::HandleAlienEvent(TEvent* event) { CHandlerIterator iter(fHeadCohandler); for (TEvtHandler* aHandler = iter.FirstHandler(); iter.More(); aHandler = iter.NextHandler()) if (aHandler->DoCoHandlerEvent(event)) break; } //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand pascal void TApplication::HandleDiskEvent(TToolboxEvent* event) { const Point topLeft(0x50, 0x70); short err; if (HiWord(event->fEventRecord.message) != noErr) { err = DIBadMount(topLeft, event->fEventRecord.message);// ??? do something with the error #if qDebugMsg if (err != noErr) fprintf(stderr, "error from DIBadMount is %d\n", err); #endif } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::DoEvent(EvtNumber, TEvtHandler* , TEvent* event)// override { FailInfo fi; VOLATILE(event); #if qDebug if (gReportEvt && event) event->ReportEvent(); #endif if (fi.Try()) { this->DispatchEvent(event); fi.Success(); } else // Recover { this->PostDoEvent(event); fi.ReSignal(); } this->PostDoEvent(event); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFinder pascal void TApplication::HandleFinderRequest(void) { #if !qNeedsAppleEventMgr AppFile anAppFile; TFile * aFile; TList * aFileList; CmdNumber cmd; FailInfo outerFi, fi; long message; short theFileCount; Boolean finderPrinting; VOLATILE(aFile); VOLATILE(message); VOLATILE(anAppFile); VOLATILE(cmd); if (outerFi.Try()) { #if qDebugMsg if (gExperimenting) fprintf(stderr, "File count: %d\n", theFileCount); #endif // determine number of files and whether it's a print from finder request CountAppFiles((short)message, theFileCount); finderPrinting = (message == appPrint); if (theFileCount == 0) { if (IsOptionKeyDown()) this->HandleMenuCommand(cOpen); else if (fLaunchWithNewDocument) this->HandleMenuCommand(cFinderNew); } else /* it's an OPEN or PRINT of 1 or more existing files */ { if (finderPrinting) cmd = cFinderPrint; else cmd = cFinderOpen; aFileList = NewList(); for (short i = 1; i <= theFileCount; ++i) { if (fi.Try()) { aFile = this->DoMakeFile(cmd); GetAppFiles(i, anAppFile); FailOSErr(aFile->IdentifyByTrio(anAppFile.vRefNum, 0, (Str63)anAppFile.fName)); aFile->fFileType = anAppFile.fType; if (this->CanOpenDocument(cmd, aFile)) { ClrAppFiles(i); aFileList->InsertLast(aFile); } else Failure(errNotMyType, 0); fi.Success(); } else // Recover { if (fi.error != noErr) { aFile = (TFile *)(FreeIfObject(aFile)); if (message == 0) { gErrorParm3 = (Str255)anAppFile.fName; if (cmd == cFinderPrint) message = msgPrintFailed; else message = msgOpenFailed; } this->ShowError(fi.error, message); } } } if (finderPrinting) { TPDocCommand* aPDocCommand; aPDocCommand = new TPDocCommand; aPDocCommand->IPDocCommand(cFinderPrint, aFileList); this->PostCommand(aPDocCommand); } else { TODocCommand * anODocCommand; anODocCommand = new TODocCommand; anODocCommand->IODocCommand(cFinderOpen, aFileList); this->PostCommand(anODocCommand); } } outerFi.Success(); } else // Recover { if (outerFi.error != noErr) this->ShowError(outerFi.error, message); // PollEvents' error handler not in place yet } #endif } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes // Assume that the high level event received was an Apple Event and process it. This will // dispatch to us via MAGeneralDispatch. pascal void TApplication::HandleHighLevelEvent(TToolboxEvent* event) { EventRecord anEventRecord; OSErr theErr; this->SetupTheMenus(); // Make sure that the menus are setup // correctly before we handle the event anEventRecord = event->fEventRecord; theErr = AEProcessAppleEvent(anEventRecord); if (theErr != errAEEventNotHandled) // If the event is one we don't handle, do nothing FailOSErr(theErr); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::HandleKeyDownEvent(TToolboxEvent* event) { this->GetTarget()->KeyEventToComponents(event);// Find out what keys were _REALLY_ pressed if (event->fCmdKey) this->GetTarget()->HandleCommandKey(event); else this->GetTarget()->HandleKeyCommand(event); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::HandleMouseDown(TToolboxEvent* event) { TWindow * aWindow; WindowPtr aWMgrWindow; short whereMouseDown; EventRecord anEventRecord; whereMouseDown = FindWindow(event->fEventRecord.where, aWMgrWindow); event->fClickCount = this->CountClicks(event, whereMouseDown); aWindow = this->WMgrToWindow(aWMgrWindow); if (((whereMouseDown == inMenuBar) && (this->InModalMenuState())) || ((whereMouseDown != inMenuBar) && this->InModalState() && (aWindow != (this->GetActiveWindow())))) { this->Beep(2); return (); // exit(HandleMouseDown); } switch (whereMouseDown) { case inMenuBar: this->SetupTheMenus(); // gives application a chance to setup individual menu items this->MenuEvent(MenuSelect(event->fEventRecord.where)); break; case inSysWindow: anEventRecord = event->fEventRecord; SystemClick(anEventRecord, aWMgrWindow); break; default: // if a MacApp window was associated with the WindowPtr then let the window object decide // what to do with the mouse click if (aWindow) { if (aWindow->Focus()) // if we can't focus, we're in trouble { VPoint theMouse(event->fEventRecord.where); aWindow->SuperToLocal(theMouse); aWindow->HandleMouseDown(theMouse, event, gStdHysteresis); } else if (qDebug) ProgramBreak("In TApplication.HandleMouseDown: couldn''t focus on a window object!"); } else this->HandleAlienEvent(event); break; } fLastUpTime = TickCount(); // Because the toolbox often eats mouseUpEvents remember the time on the way out for // double/ triple detection. } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::HandleMouseUp(TToolboxEvent* event) { TWindow * aWindow; WindowPtr aWMgrWindow; short whereMouseDown; // Remember time of last mouse up, in order to detect double/triple (multiple) clicks fLastUpTime = event->fEventRecord.when; whereMouseDown = FindWindow(event->fEventRecord.where, aWMgrWindow); aWindow = this->WMgrToWindow(aWMgrWindow); switch (whereMouseDown) { case inMenuBar: break; case inSysWindow: break; default: if (aWindow == NULL) this->HandleAlienEvent(event); // handle non-MacApp windows break; } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::HandleSystemEvent(TToolboxEvent* event) { WindowPtr aWindowPtr; TWindow * aWindow; Boolean switchingIn; Boolean convertClipboard; switch (((unsigned long)(event->fEventRecord.message & osEvtMessageMask)) >> 24) { case suspendResumeMessage: switchingIn = ((event->fEventRecord.message) & resumeFlag) != 0; convertClipboard = ((event->fEventRecord.message) & convertClipboardFlag) != 0; if (switchingIn) this->RegainControl(convertClipboard); else this->AboutToLoseControl(convertClipboard); if (switchingIn) aWindow = this->GetFrontWindow(); else aWindow = this->GetActiveWindow(); if (aWindow) aWindow->Activate(switchingIn); // when switching out, after having hid windows that get hid on suspend in // AboutToLoseControl, we need to ensure that our idea about the front window // and the Process Manager's idea about the front window are the same if (!switchingIn) { aWindowPtr = MAFrontWindow(); if (aWindowPtr) BringToFront(aWindowPtr); } if (!(qNeedsProcessMgr || gConfiguration.hasProcessMgr)) fInBackground =!switchingIn; this->InvalidateMouseRegions(); break; case mouseMovedMessage: event->fAffectsMenus = FALSE; // We don't think mouse tracking usually bothers the menus. // We got the mouse moved event because the mouse strayed outside of fSleepRgn. It may or // may not have strayed outside of the other mouse regions. We'll only // invalidate them here (if necessary) because that way we can defer computing // them for as long as possible. if (!PtInRgn(event->fEventRecord.where, fCursorRgn)) this->InvalidateCursorRgn(); if (!PtInRgn(event->fEventRecord.where, fHelpRgn)) this->InvalidateHelpRgn(); break; default: if (gIntenseDebugging) fprintf(stderr, "in TApplication.HandleSystemEvent: got unrecognized event\n"); break; } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::HandleUpdateEvent(TToolboxEvent* event) { TWindow * aWindow; aWindow = this->WMgrToWindow((WindowPtr) event->fEventRecord.message); if (aWindow) aWindow->Update(); else this->HandleAlienEvent(event); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::Idle(IdlePhase phase) { FailInfo fi; #if qDebug Boolean wasTrcEnable; #endif if (fi.Try()) { #if qDebug wasTrcEnable = TrcEnable(gTraceIdle); // Trace during idle only if user wants to. #endif if (phase == idleBegin) { if (!gInFilter && MemSpaceIsLow()) this->SpaceIsLow(); else fNextSpaceMsg = TickCount(); } // Create a new block for failure handling { CHandlerIterator iter(fHeadCohandler); for (TEvtHandler* aHandler = iter.FirstHandler(); iter.More(); aHandler = iter.NextHandler()) aHandler->HandleIdle(phase); } if (qDebug) Assertion(this->GetTarget() != NULL, "GetTarget != nil"); // Create a new block for failure handling { CHandlerIterator iter(this->GetTarget()); for (TEvtHandler* aHandler = iter.FirstHandler(); iter.More(); aHandler = iter.NextHandler()) aHandler->HandleIdle(phase); } #if qDebug TrcEnable(wasTrcEnable); // restore tracing state at end of idle. #endif fi.Success(); } else // Recover { gInhibitNestedHandling = TRUE; // Don't want to come back into Idle From // alert filters or other strange places fi.ReSignal(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal long TApplication::GetWaitTicks(Boolean allowApplicationToSleep) { const short kMaxSleep = 60; // max sleep in foreground so MultiFinder // gives time to non-desk accessory drivers #if qDebug Boolean wasTrcEnable; #endif long returnValue = 0; #if qDebug wasTrcEnable = TrcEnable(gTraceIdle); // Trace during idle only if user wants to. #endif if (allowApplicationToSleep) { long compositeTicks = kMaxIdleTime; // Check the cohandler chain first. Add new block for failure handling { CHandlerIterator iter(fHeadCohandler); for (TEvtHandler* aHandler = iter.FirstHandler(); iter.More(); aHandler = iter.NextHandler()) compositeTicks = Min(compositeTicks, Max(aHandler->NextIdle() - TickCount(), 0)); } if (qDebug) Assertion(this->GetTarget() != NULL, "GetTarget != nil"); // now run through the target chain. Add new block for failure handling { CHandlerIterator iter(this->GetTarget()); for (TEvtHandler* aHandler = iter.FirstHandler(); iter.More(); aHandler = iter.NextHandler()) compositeTicks = Min(compositeTicks, Max(aHandler->NextIdle() - TickCount(), 0)); } // faceless driver bug in M.F fixed in process manager if (qNeedsProcessMgr || gConfiguration.hasProcessMgr) returnValue = compositeTicks; else if ((compositeTicks > kMaxSleep) && this->IsFrontProcess()) { if (gIntenseDebugging && gReportEvt) fprintf(stderr, "IN TApplication.GetWaitTicks: clipped to MaxSleep=%d\n", kMaxSleep); returnValue = Min(compositeTicks, kMaxSleep); } } #if qDebug TrcEnable(wasTrcEnable); // restore tracing state at end of idle. #endif return returnValue; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal Boolean TApplication::InModalState(void) { TWindow * aWindow; WindowPtr aWindowPtr; aWindowPtr = FrontWindow(); // in case the front window is an alert or something if ((this->WMgrToWindow(aWindowPtr) == NULL) && (aWindowPtr)) switch (GetWindowVariant(aWindowPtr)) { case dBoxProc: case plainDBox: case altDBoxProc: return TRUE; default: return FALSE; } else { aWindow = this->GetActiveWindow(); return ((aWindow) && (aWindow->fIsModal)); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal Boolean TApplication::InModalMenuState(void) { TWindow * aWindow; WindowPtr aWindowPtr; aWindowPtr = FrontWindow(); // in case the front window is an alert or something if ((this->WMgrToWindow(aWindowPtr) == NULL) && (aWindowPtr)) switch (GetWindowVariant(aWindowPtr)) { case dBoxProc: case plainDBox: case altDBoxProc: return TRUE; default: return FALSE; } else { aWindow = this->GetActiveWindow(); return ((aWindow) && !aWindow->AllowsMenuAccess()); } } //-------------------------------------------------------------------------------------------------- #pragma segment MANonRes pascal void TApplication::InstallCohandler(TEvtHandler* aCohandler, Boolean addIt) { if (addIt) fHeadCohandler = aCohandler->AddHandler(fHeadCohandler); else fHeadCohandler = aCohandler->RemoveHandler(fHeadCohandler); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal Boolean TApplication::IsDeskAccessory(WindowPtr aWMgrWindow) { return (!(qNeedsProcessMgr || gConfiguration.hasProcessMgr) && ((aWMgrWindow) && (WindowPeek(aWMgrWindow)->windowKind < 0))); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal Boolean TApplication::IsFrontProcess(void) { ProcessSerialNumber aPSN; ProcessSerialNumber applicationPSN; Boolean result; if (qNeedsProcessMgr || gConfiguration.hasProcessMgr) { FailOSErr(GetFrontProcess(aPSN)); applicationPSN = fApplicationPSN; FailOSErr(SameProcess(aPSN, applicationPSN, result)); return result; } else return !fInBackground; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::MakeFrontProcess(void) { if (!this->IsFrontProcess()) { ProcessSerialNumber aPSN = fApplicationPSN; FailOSErr(SetFrontProcess(aPSN)); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal Boolean TApplication::IsHelpEnabled(void) { if (qNeedsHelpMgr || gConfiguration.hasHelpMgr) return HMGetBalloons(); else return FALSE; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::InvalidateMouseRegions(void) { this->InvalidateCursorRgn(); this->InvalidateHelpRgn(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::InvalidateCursorRgn(void) { if (fCursorRgn) SetEmptyRgn(fCursorRgn); // Make sure it gets changed back // ###!!! most callers of invalidatecursorrgn really would want the help rgn invalidated // for the same reasons that the cursor rgn is invalid. Until we get them all switched // over to a new call like "InvalidateMouseRgns" we should just inval the help rgn too } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::InvalidateHelpRgn(void) { if (fHelpRgn) SetEmptyRgn(fHelpRgn); // Make sure it gets changed back if (qNeedsHelpMgr || gConfiguration.hasHelpMgr) if (HMIsBalloon()) { OSErr err = HMRemoveBalloon(); if (err != hmNoBalloonUp) FailOSErr(err); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::InvalidateFocus(void) { if (gFocusedView) gFocusedView->InvalidateFocus(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal Boolean TApplication::IsCursorRgnInvalid(void) { // The cursor is normally tracked via MouseMoved events. But for those with special needs // fAlwaysTrackCursor can come to the rescue. return (EmptyRgn(fCursorRgn) || fAlwaysTrackCursor); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal Boolean TApplication::IsHelpRgnInvalid(void) { return EmptyRgn(fHelpRgn); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::KeyEventToComponents(TToolboxEvent* event) // See Tech Note #263 for the reason for this abomination { const short kMaskModifier = 0xFE00; // need to strip command key from Modifiers const long kMaskASCII1 = 0x000000FF; // get key from KeyTrans return const long kMaskASCII2 = 0x00FF0000; // get key from KeyTrans return const short kPeriod = '.'; const short kUpKeyMask = 0x0080; const short kMAsmKeyCache = 38; /*!!! Replace with system supplied constant when sys 7.0 headers ship */ // !!! Delete this record for 7.0 only operation. This is really a private record so // _DON'T_ use any other fields! struct MAExpandMemRec { short emVersion; // version of expanded memory long emSize; // length of em long emIntlGlobals; // international globals pointer long emKeyDeadState; // Key1Trans, Key2Trans dead state Ptr emKeyCache; // KCHR keyboard cache long emIntlDef; // Reserved for Intl Boolean emFirstKeyboard; // flag byte Boolean emAlign; // long-align until we need this storage long emItlCache[4]; // bytes in cache Boolean emItlNeedUnlock; // for pack6 Boolean emItlDirectGetIntl; // for pack6 unsigned char emFiller[22]; // Reserved room }; typedef struct MAExpandMemRec MAExpandMemRec; typedef MAExpandMemRec* MAExpandMemRecPtr, ** MAExpandMemRecHandle; short keyCodeParameter; // See IM-V pp. 195 long keyInfo; long state; Ptr keyTransTable; inherited::KeyEventToComponents(event); // Get default translation, if any EventRecord& recordData = event->fEventRecord; if ((recordData.what == keyDown) || (recordData.what == autoKey)) { // Now see if the command key is down. If it is, get the correct ASCII translation by // masking the command key out and re-translating because the command key will // mask the shift modifier. if (event->fCmdKey) { // set the upkey bit so KeyTrans doesn't do special deadkey processing keyCodeParameter = ((((recordData.modifiers) & kMaskModifier) | event->fKeyCode) | kUpKeyMask); state = 0; // Get the correct keytable pointer. We don't want to grope the system unnecessarily so // use the script managers improvements if they're there. if (gConfiguration.systemVersion >= 0x700) keyTransTable = (Ptr)(GetEnvirons(kMAsmKeyCache)); else // Fake handle. the lomem address is a pointer to the table keyTransTable = (Ptr)((*(MAExpandMemRecHandle)(ExpandMem))->emKeyCache); keyInfo = KeyTrans(keyTransTable, keyCodeParameter, state); event->fCharacter = (unsigned char)(((keyInfo) & kMaskASCII1)); if (event->fCharacter == (unsigned char)(0)) event->fCharacter = (unsigned char)((keyInfo >> kMaskASCII2) & 16); } } } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal CmdNumber TApplication::KindOfDocument(CmdNumber itsCmdNumber, TFile*) { return itsCmdNumber; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes // must be in the main segment pascal void TApplication::MainEventLoop(void) { fIdlePhase = idleBegin; while (!fAppDone) { if (fIdlePhase == idleBegin) UnloadAllSegments(); // don't unload segs after idle has begun // ??? should we (1) unload segs after completing idle but before doing the event? (2) // unload segs while processing event during background printing? this->PollEvent(kAllowApplicationToSleep); } // fAppDone is a Boolean; that we set TRUE when the user chooses 'Quit' } //-------------------------------------------------------------------------------------------------- #pragma segment MAClipboard pascal TView* TApplication::MakeViewForAlienClipboard(void) { return NULL; // use defaults } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal void TApplication::MenuEvent(long menuItem) { FailInfo fi; CmdNumber cmd; Str255 deskAccName; short theMenuNumber; short theItemNumber; theMenuNumber = HiWord(menuItem); theItemNumber = LoWord(menuItem); VOLATILE(cmd); if (theMenuNumber != 0) { cmd = CmdFromMenuItem(theMenuNumber, theItemNumber); #if qDebugMsg if (cmd == cCantUndo) { fprintf(stderr, "Command number %d is reserved for MacApp.\n", cCantUndo); ProgramBreak("Use of reserved command number."); } if (gReportMenuChoices && (cmd > 0)) fprintf(stderr, "Menu Choice Command Number == %d\n", cmd); #endif if ((cmd < 0) && (theMenuNumber == mApple)) { GetItem(MAGetMenu(mApple), theItemNumber, deskAccName); this->OpenDeskAccessory(deskAccName); } else if ((cmd < cEditBase) || (cmd > cEditLast) || (!SystemEdit((short)(cmd - cEditBase)))) { if (fi.Try()) { if (fSysWindowActive) this->ActivateBusyCursor(TRUE); this->GetTarget()->HandleMenuCommand(cmd); if (fSysWindowActive) this->ActivateBusyCursor(FALSE); fi.Success(); } else // Recover { if (fSysWindowActive) this->ActivateBusyCursor(FALSE); FailNewMessage(fi.error, fi.message, BuildMessage((short)cmd, msgCmdErr)); fi.ReSignal(); } } } } //-------------------------------------------------------------------------------------------------- #pragma segment MASelCommand pascal Boolean IsOpen(short itsID, void*) { DCtlHandle dceHnd; if ((itsID >= 0) && (itsID < GetUnitNtryCnt())) { dceHnd = (*GetUTableBase())[itsID]; return ((dceHnd) && ((((*dceHnd)->dCtlFlags) & 0x0400) != 0)); } else return FALSE; } pascal void TApplication::OpenDeskAccessory(const Str255& deskAccName) { short aRefNum; Handle drvrH; short theID; ResType theType; Str255 theName; Boolean oldPerm; Boolean ourHeap; FailInfo fi; GrafPtr savedPort; VOLATILE(aRefNum); // then go ahead and open it; it's in a separate process if (qNeedsProcessMgr || gConfiguration.hasProcessMgr) { GetPort(savedPort); aRefNum = OpenDeskAcc(deskAccName); SetPort(savedPort); } else { if (fi.Try()) { aRefNum = 0; // Make sure failure handler works. // Attempt to load the DA into memory. If 'deskAccName' refers to another app // rather than a real desk acc, then GetNamedResource returns a faked up handle // courtesy of MultiFinder™. We open the DA with permanent allocation so as to // ensure that we don't take space from our code segments. oldPerm = PermAllocation(TRUE); drvrH = GetNamedResource('DRVR', deskAccName); PermAllocation(oldPerm); FailNILResource(drvrH); // Either there wasn't enough memory // …to load the DA, or something is // …seriously wrong. // At this point if we are really opening a DA we know it fits in memory. GetResInfo(drvrH, theID, theType, theName);// If it's a not a real DA then this // will generate a ResError. // Find out which zone it lives in, or if option key is down. ourHeap = ((HandleZone(drvrH) == ApplicZone()) || IsOptionKeyDown()); if ((ResError() != noErr) || // If it's a MultiFinder fake DA, IsOpen(theID, this) || // …or if the DA is already open, (!ourHeap)) // …or if it's not going in our heap { oldPerm = PermAllocation(TRUE); // In case we guess wrong GetPort(savedPort); aRefNum = OpenDeskAcc(deskAccName);// …then go ahead and open it. SetPort(savedPort); PermAllocation(oldPerm); } else { // If we get this far, we know we have a real DA and it's going into our // heap. Open it, but them make sure we have enough memory to continue // running. FailSpaceIsLow(); // In case we're already low on mem. oldPerm = PermAllocation(TRUE); // If the pig wants to wallow GetPort(savedPort); aRefNum = OpenDeskAcc(deskAccName);// Use temporary allocation. SetPort(savedPort); PermAllocation(oldPerm); FailSpaceIsLow(); // Fail if not enough memory left. FailNIL(*drvrH); // …or if the driver was purged to // …satisfy a code space requirement. } fi.Success(); } else // Recover { if (aRefNum != 0) CloseDeskAcc(aRefNum); if (fi.message == 0) { gErrorParm3 = deskAccName; // Get rid of leading null character if (gErrorParm3[1] == 0) gErrorParm3.Delete(1, 1); } FailNewMessage(fi.error, fi.message, msgOpenFailed); fi.ReSignal(); } } } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal void TApplication::OpenNew(CmdNumber itsCmdNumber) { TDocument* aDocument = NULL; TFile* aFile = NULL; Str255 newTitle; TWindow* aWindow; FailInfo fi; VOLATILE(aDocument); if (fi.Try()) { aFile = this->DoMakeFile(itsCmdNumber); aDocument = this->DoMakeDocument(this->KindOfDocument(itsCmdNumber, aFile), aFile); aDocument->DoInitialState(); aDocument->DoMakeViews(kForDisplay); aDocument->DoMakeWindows(); aDocument->UntitledName(newTitle); // For MacApp 1.1, newTitle should be always != '' if (!newTitle.IsEmpty()) aDocument->SetTitle(newTitle); else if ((aDocument->fWindowList) && (aDocument->fWindowList->GetSize() > 0)) // Grope, grope, grope { aWindow = (TWindow *)(aDocument->fWindowList->First()); aWindow->GetTitle(newTitle); newTitle = newTitle.Copy(aWindow->fPreDocname, newTitle.Length() - aWindow->fConstTitle); aFile->SetName(newTitle); } this->AddDocument(aDocument); FailSpaceIsLow(); // Fail if document leaves us with no room // Don't attempt to show the windows until we're sure we won't fail aDocument->ShowWindows(); fi.Success(); } else // Recover { aDocument = (TDocument *)FreeIfObject((TObject *)aDocument); FailNewMessage(fi.error, fi.message, msgNewFailed); fi.ReSignal(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal void TApplication::OpenOld(CmdNumber itsOpenCmd, TFile* aFile) // Called for opening a document, given its name { TDocument* aDocument = NULL; TDocument* otherDoc; Size oldCodeReserve, oldMemReserve; FailInfo fi; VOLATILE(aDocument); VOLATILE(oldCodeReserve); VOLATILE(oldMemReserve); if (fi.Try()) { // Set reserve down a little to ensure that we can open existing documents GetReserveSize(oldCodeReserve, oldMemReserve); SetReserveSize(oldCodeReserve, oldMemReserve / 2); otherDoc = this->AlreadyOpen(aFile); if (!otherDoc) { aDocument = this->DoMakeDocument(this->KindOfDocument(itsOpenCmd, aFile), aFile); aDocument->ReadDocument(kForDisplay); aDocument->DoMakeViews(kForDisplay); aDocument->DoMakeWindows(); this->AddDocument(aDocument); FailSpaceIsLow(); // Fail if the document leaves us with no memory // Set the reserve back to where it was SetReserveSize(oldCodeReserve, oldMemReserve); // Don't attempt to show the windows until we're sure we won't fail aDocument->ShowWindows(); } else { otherDoc->OpenAgain(itsOpenCmd, aDocument); SetReserveSize(oldCodeReserve, oldMemReserve); } fi.Success(); } else // Recover { aDocument = (TDocument *)(FreeIfObject(aDocument)); if (fi.message == 0) aFile->GetName((Str63 &)gErrorParm3); // Set the reserve back to where it was SetReserveSize(oldCodeReserve, oldMemReserve); FailNewMessage(fi.error, fi.message, msgOpenFailed); fi.ReSignal(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::ProcessEvent(TEvent* event) { #if qDebug MAName aMAName; #endif if (qDebug && (event == NULL)) ProgramBreak("NULL passed to TApplication::ProcessEvent"); else if (qDebug && (!IsObject(event))) // since it's possible to have passed in a freed undoable command allocated in a global // variable (due to pilot error) { VerboseIsObject(event); ProgramBreak("bogus object passed to TApplication::ProcessEvent"); } else { #if qDebug if (gIntenseDebugging) { event->GetClassName(aMAName); fprintf(stderr, "The Event to process: %s\n", (char *) aMAName); } #endif } if (event) event->Process(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::PerformCommand(TCommand* command) // OVERRIDE { FailInfo fi; Boolean saveCmd; VPoint initialPt; #if qDebug MAName aMAName; #endif short aCmdNumber; VOLATILE(aCmdNumber); VOLATILE(command); if (qDebug && !command) ProgramBreak("NULL passed to TApplication.PerformCommand"); else if (qDebug && (!IsObject(command))) /* since it's possible to have passed in a freed undoable command allocated in a global variable (due to pilot error) */ { VerboseIsObject(command); ProgramBreak("bogus object passed to TApplication.PerformCommand"); } else { #if qDebugMsg if (gIntenseDebugging) { command->GetClassName(aMAName); fprintf(stderr, "The Command to perform: %s\n", (char *) aMAName); } #endif if (command) { saveCmd = (command) && (command->fCausesChange || command->fCanUndo); if (saveCmd) { this->CommitLastCommand(); // it frees fLastCommand. If the last (fCausesChange or fCanUndo) command sets // fFreeOnCompletion to FALSE then we can // execute the same undoable command any // number of times. Non-Undoable commands // don't get FREEd here but immediately // after they're executed (that's // performed not shot) if (qDebug &&!IsObject(command)) { VerboseIsObject(command); ProgramBreak("You may not want to continue with a command that's been _FREED_!"); } } if (fi.Try()) { if (fEventLevel == 1) // Don't unload segs if in nested event handling UnloadAllSegments(); gClipboardMgr->fClipClaimed = FALSE; command->DoIt(); fi.Success(); } else // Recover { if (gClipboardMgr->fClipClaimed) { gClipboardMgr->SetClipView(gClipboardMgr->fClipUndoView); gClipboardMgr->fClipUndoView = NULL; // The newly-installed view needs to be freed also /* SwapClipViews;*/ /* Get original back there… !!! would be nice but doesn't do right thing yet */ } aCmdNumber = (short)(command->fID); if (command->ShouldFreeOnCompletion()) command = (TCommand*)(FreeIfObject(command)); if (command == fLastCommand) fLastCommand = NULL; // make sure we clear our reference FailNewMessage(fi.error, fi.message, BuildMessage(aCmdNumber, msgCmdErr)); fi.ReSignal(); } if (saveCmd) { fLastCommand = command; command->fCmdDone = TRUE; } // This is done after .DoIt, so .DoIt can change the fCausesChange flag if ((command) && command->fCausesChange && (command->fChangedObject)) command->fChangedObject->Changed(command->GetChangeID(), command);/* Notify the proper object that a change has occurred */ if (!saveCmd && command->ShouldFreeOnCompletion()) command = (TCommand*)FreeIfObject(command); } } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::PollEvent(Boolean allowApplicationToSleep) { FailInfo fi; TEvent* retrievedEvent; Boolean didAllowApplicationToSleep = fAllowApplicationToSleep; VOLATILE(didAllowApplicationToSleep); fAllowApplicationToSleep = allowApplicationToSleep; ++fEventLevel; #if qDebugMsg if (this->GetTarget() == NULL) fprintf(stderr, "Serious Error!!! in TApplication.PollEvent: target == NULL\n"); #endif if (fi.Try()) { retrievedEvent = this->RetrieveAnEvent(); if (retrievedEvent) this->ProcessEvent(retrievedEvent); /* The desk scrap may have been changed by use of Cmd-X or Cmd-C in desk accessories. */ if (fSysWindowActive) { gClipboardMgr->CheckDeskScrap(); this->InvalidateFocus(); } fi.Success(); --fEventLevel; if (fEventLevel == 0) gInhibitNestedHandling = FALSE; // All clear } else // Recover { #if qDebugMsg fprintf(stderr, "\n"); // add a blank line after all the messages from Failure #endif fAllowApplicationToSleep = didAllowApplicationToSleep; --fEventLevel; if (fEventLevel == 0) { if (fi.error != noErr) { UnloadAllSegments(); this->ShowError(fi.error, fi.message); } InvalidateMenus(); } } fAllowApplicationToSleep = didAllowApplicationToSleep; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::PollToolboxEvent(Boolean allowApplicationToSleep) { EventRecord theEvent; TToolboxEvent * event; long waitTicks; RgnHandle sleepRgn; if (EventAvail(fMainEventMask, theEvent)) // If any waiting Events (keystrokes, mousedowns) we won't be sleeping anyway { sleepRgn = NULL; waitTicks = 0; } else { this->SetupTheMenus(); sleepRgn = this->GetSleepRgn(); waitTicks = this->GetWaitTicks(allowApplicationToSleep);// calc last so it's most accurate } HiliteMenu(0); // Cleanup any menu titles left hilited. Done here so titles stay hilited until // synchronous actions are performed. event = this->GetEvent(fMainEventMask, waitTicks, sleepRgn); if (event) { /* GetEvent returned an event (work to do). If we were idling before then we must keep the calls balanced with an IdleEnd to because we are no longer idling */ if (fIdlePhase == idleContinue) { this->Idle(idleEnd); fIdlePhase = idleBegin; } this->PostAnEvent(event); } else // Woke up with no event available. Truly idle { this->Idle(fIdlePhase); fIdlePhase = idleContinue; } if (qDebug) gErrorParm3 = "?????"; // to prevent anyone from using old values } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::PostAnEvent(TEvent* event) // Override { Boolean oldObjectPerm; oldObjectPerm = AllocateObjectsFromPerm(FALSE); fEventList->Insert(event); // inserts event ordered the list AllocateObjectsFromPerm(oldObjectPerm); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::PostCommand(TCommand* command) // Override { ///!!! Left in for compatibility this->PostAnEvent(command); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::PostDoEvent(TEvent* event) { Boolean perm; if (event && event->fAffectsMenus) InvalidateMenus(); perm = PermAllocation(FALSE); #if qDebug if (perm) ProgramBreak("The permanent flag was left TRUE."); #endif // See if a system window has been activated or deactivated. if (!(qNeedsProcessMgr || gConfiguration.hasProcessMgr) && (fSysWindowActive != this->IsDeskAccessory(FrontWindow()))) { fSysWindowActive =!fSysWindowActive; if (fSysWindowActive) // deactivating to sys window { this->AboutToLoseControl(TRUE); InvalidateMenuBar(); } else // coming back from sys window this->RegainControl(TRUE); } if (event && (event->ShouldFreeOnCompletion())) //!!!RCR event = (TEvent *)FreeIfObject(event); } //-------------------------------------------------------------------------------------------------- #pragma segment MAFinder pascal Boolean TApplication::PrintDocument(TFile* aFile) { TDocument* aDocument = NULL; FailInfo fi; VOLATILE(aDocument); if (fi.Try()) { aDocument = this->DoMakeDocument(this->KindOfDocument(cFinderPrint, aFile), aFile); aDocument->ReadDocument(kForPrinting); aDocument->DoMakeViews(kForPrinting); // Note that if we are finder printing, this segment will be resident UnloadAllSegments(); gFinderPrintingProceed = TRUE; // set in TStdPrintHandler::DoPrintCommand aDocument->HandleMenuCommand(cFinderPrint); UnloadAllSegments(); fi.Success(); } else // Recover { aDocument = (TDocument *)FreeIfObject(aDocument); fi.ReSignal(); } aDocument = (TDocument *)FreeIfObject(aDocument); UnloadAllSegments(); return gFinderPrintingProceed; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::RegainControl(Boolean checkClipboard) { CWMgrIterator iter; this->ActivateBusyCursor(TRUE); gClipboardMgr->RegainControl(checkClipboard); // Let all windows know that we're regaining control - e.g. so floaters can show themselves for (WindowPtr aWinPtr = iter.FirstWMgrWindow(); iter.More(); aWinPtr = iter.NextWMgrWindow()) { TWindow* aWindow = this->WMgrToWindow(aWinPtr); if (aWindow) aWindow->RegainControl(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes // must be in the main segment pascal void TApplication::Run(void) { UnloadAllSegments(); FailSpaceIsLow(); // make sure we have enough memory to continue gInitialized = TRUE; // was set FALSE in InitToolBox gClipboardMgr->Launch(); // Launch after segments are unloaded since reading the scrap may be piggy // I know this looks funny but this does cover the case where we are built for // system 6.0 but are running on system 7.0. In that case we still don't want // to HandleFinderRequest. However if we are built for system 7.0 then this // code will be conditionally compiled out if (!gConfiguration.hasAppleEventMgr) { UnloadAllSegments(); this->HandleFinderRequest(); } UnloadAllSegments(); fEventLevel = 0; // Indicate outermost level this->MainEventLoop(); // runs until a quit command this->AboutToLoseControl(TRUE); #if qDebug /* See if previous max. resource usage has been exceeded by the termi- nation code and resources. */ CheckRsrcUsage(); #endif // We must call CleanupMacApp here; if we wait to fall thru to the end of the main // program, A5 has been invalidated and we can't refer to any globals. CleanupMacApp(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::SelectWMgrWindow(WindowPtr aWMgrWindow) { SelectWindow(aWMgrWindow); // Simply call the toolbox to select it. fLastClickPart = inDesk; // Make sure previous mouse clicks are not // are not considered part of a multi-click. } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::SetTarget(TEvtHandler* newTarget) { if (newTarget == NULL) { newTarget = this; #if qDebug ProgramBreak("In TApplication.SetTarget… you''re setting the global target to nil!"); #endif } if (newTarget != fTarget) { fTarget->ResignedApplicationTarget(); fTarget = newTarget; fTarget->BecameApplicationTarget(); this->InvalidateMouseRegions(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::SetUndoText(Boolean cmdDone, CmdNumber aCmdNumber) { short newMenuState; Str255 undoName; Str255 cmdName; short preCmdName; short constChars; if ((fUndoState != cmdDone) || (fUndoCmd != aCmdNumber)) { if (aCmdNumber == cCantUndo) newMenuState = bzCantUndo; else if (cmdDone) newMenuState = bzUndo; else newMenuState = bzRedo; GetIndString(undoName, kIDBuzzString, newMenuState); if (ParseTitleTemplate(undoName, preCmdName, constChars)) { if ((aCmdNumber == cNoCommand) || (aCmdNumber == cCantUndo)) cmdName = ""; else CmdToName(aCmdNumber, cmdName); SubstituteInTitle(undoName, cmdName, preCmdName, constChars); } SetCmdName(cUndo, undoName); fUndoState = cmdDone; fUndoCmd = aCmdNumber; } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes class CSetupTheMenus { // Fields TApplication* fApplication; public: // Constructor CSetupTheMenus(TApplication* theApplication) : fApplication(theApplication) { } // Method pascal void DoSetup(void); }; //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void CSetupTheMenus::DoSetup(void) { Boolean undoState; CmdNumber undoCmd; TWindow * aWindow = NULL; TCommand * lastCommand = NULL; #if qInspector Boolean lowSpace; #endif if (!fApplication->InModalMenuState()) { #if qInspector lowSpace = MemSpaceIsLow(); #endif aWindow = fApplication->GetActiveWindow(); //!!!RCR fApplication->GetTarget()->HandleSetupMenus();// Setup menus relevent to target chain // Set up the menu commands that are not dependent on the target chain… undoState = kShowCantUndo; // Set the Undo menu defaults. undoCmd = cCantUndo; if (fApplication->fSysWindowActive) { undoState = kShowUndo; undoCmd = cNoCommand; Enable(cUndo, TRUE); Enable(cCut, TRUE); Enable(cCopy, TRUE); Enable(cPaste, TRUE); Enable(cClear, TRUE); } else { lastCommand = fApplication->GetTarget()->GetLastCommand(); if (lastCommand) if (lastCommand->fCanUndo) { if (lastCommand->fCmdDone) undoState = kShowUndo; else undoState = kShowRedo; undoCmd = lastCommand->fID; /* Enable Undo only if the last command was not document-specific or the document changed is the current document. */ /* Enable(cUndo, (lastCommand->fChangedDocument == NULL) || ((aWindow) && (lastCommand->fChangedDocument == aWindow->fDocument)));*/ //!!!MEB Enable(cUndo, (!(lastCommand->fChangedObject && (lastCommand->fChangedObject->IsMemberClass(GetClassIDFromName("TDocument"))))) || ((aWindow) && (lastCommand->fChangedObject == aWindow->fDocument))); } } fApplication->SetUndoText(undoState, undoCmd); /*!!! we should really just make a call to the debugger/inspector here and give them a shot at setting these up instead */ #if qDebug EnableCheck(cExperimenting, TRUE, gExperimenting); EnableCheck(cReportEvt, TRUE, gReportEvt); EnableCheck(cDebugPrinting, TRUE, gDebugPrinting); EnableCheck(cReportMenuChoices, TRUE, gReportMenuChoices); EnableCheck(cIntenseDebugging, TRUE, gIntenseDebugging); Enable(cEnterMacAppDebugger, TRUE); if (aWindow) { Enable(cModalToggle, TRUE); SetMenuState(cModalToggle, kDebugBuzzStrings, bzMakeModal, bzMakeModeless, aWindow->fIsModal); Enable(cRefreshFrontWindow, TRUE); Enable(cDoFirstClick, TRUE); SetMenuState(cDoFirstClick, kDebugBuzzStrings, bzDoFirstClick, bzDontDoFirstClick, aWindow->fDoFirstClick); } // System Justification Enable(cSetSysJust, TRUE); SetMenuState(cSetSysJust, kDebugBuzzStrings, bzSetRightSysJust, bzSetLeftSysJust, GetActualJustification(teFlushDefault) != teFlushLeft); EnableCheck(cTraceSetupMenus, TRUE, gTraceSetupMenus); EnableCheck(cTraceIdle, TRUE, gTraceIdle); Enable(cDebugWind, TRUE); #endif #if qInspector Enable(cNewInspectorWindow, !lowSpace); #endif } MenuHandle appleMenu = MAGetMenu(mApple); if (((*appleMenu)->enableFlags & 1) == fApplication->InModalState()) { (*appleMenu)->enableFlags = ((*appleMenu)->enableFlags ^ 1); InvalidateMenuBar(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::SetupTheMenus(void) { CSetupTheMenus aCSetupTheMenus(this); if (this->IsFrontProcess() && (MenusHavePendingUpdate() || MenuBarHasPendingUpdate())) PerformMenuSetup((DoToVoidType) & CSetupTheMenus::DoSetup, &aCSetupTheMenus); } /* SetupTheMenus */ //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal void TApplication::SFGetParms(CmdNumber, ProcPtr& fileFilter, TypeListHandle typeList, short& dlgID, Point& where, ProcPtr& dlgHook, ProcPtr& modalFilter, Ptr& activeList, ProcPtr& activateProc, Ptr yourDataPtr) { DialogTHndl dlogTemplate; Rect dialogRect; if (qNeedsAliasMgr || gConfiguration.hasAliasMgr) { dlgID = sfGetDialogID; where = Point(-1,-1); } else { dlgID = getDlgID; // getDlgID defined by Standard File dlogTemplate = (DialogTHndl)(GetResource('DLOG', dlgID)); if (dlogTemplate) { dialogRect = (*dlogTemplate)->boundsRect; CenterRectOnScreen(dialogRect, TRUE, TRUE, TRUE); where = dialogRect[topLeft]; } else where = Point(100,100); } SetHandleSize((Handle)typeList, 4); FailMemError(); (**typeList)[0] = fMainFileType; fileFilter = NULL; dlgHook = NULL; modalFilter = NULL; activeList = NULL; activateProc = NULL; yourDataPtr = NULL; } /* SFGetParms */ //-------------------------------------------------------------------------------------------------- #pragma segment MAError pascal void TApplication::ShowError(OSErr error, long message) { ErrorAlert(error, message); } /* ShowError */ //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::SpaceIsLow(void) { long now; if (fEventLevel == 1) /* Don't unload segs if nested event handling*/ UnloadAllSegments(); // Show 'space is low' alert only after ever fLowSpaceInterval ticks. if ((fLowSpaceInterval > 0) && this->IsFrontProcess()) { now = TickCount(); if (now > fNextSpaceMsg) { gInhibitNestedHandling = TRUE; // Don't tell em again from the alert StdAlert(phSpaceIsLow); fNextSpaceMsg = now + fLowSpaceInterval; } } } /* SpaceIsLow */ //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::DoSetCursor(Point globalMouse, RgnHandle cursorRgn) { this->GetDefaultCursorRgn(globalMouse, cursorRgn); SetCursor(qd.arrow); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal TView* TApplication::HandleCursor(Point globalMouse, RgnHandle cursorRgn) { WindowPtr aWMgrWindow; TWindow * cursorWindow; TView * cursorView; if (FindWindow(globalMouse, aWMgrWindow) == inContent) { cursorWindow = this->WMgrToWindow(aWMgrWindow); if ((cursorWindow) && cursorWindow->HandlesCursor()) { VPoint windowVPt(globalMouse); cursorWindow->SuperToLocal(windowVPt); cursorView = cursorWindow->HandleCursor(windowVPt, fCursorRgn); // Convert cursor region from view coords to global coords if ((cursorView) && !EmptyRgn(cursorRgn)) { VPoint viewVPt = gZeroVPt; cursorView->LocalToWindow(viewVPt); cursorWindow->LocalToSuper(viewVPt); OffsetRgn(cursorRgn, (short) viewVPt.h, (short) viewVPt.v); } return cursorView; } } else return NULL; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::TrackCursor(Point globalMouse) { TView * cursorView; #if qDebugMsg if (PtInRgn(globalMouse, fCursorRgn)) { if (gIntenseDebugging && gTraceIdle) fprintf(stderr, "cursor is in cursor region\n"); } #endif this->InvalidateCursorRgn(); /* Find out if the cursor is in a window which handles the cursor, and if so, call HandleCursor to find the view which claimed the cursor, and the region it computed. */ cursorView = this->HandleCursor(globalMouse,fCursorRgn); if (EmptyRgn(fCursorRgn)) this->DoSetCursor(globalMouse,fCursorRgn); // Make sure the cursorpoint is included PtAndRgn(globalMouse, fCursorRgn); #if qDebugMsg if (gIntenseDebugging && gTraceIdle) if (fCursorRgn == NULL) fprintf(stderr, "fCursorRgn is NULL\n"); else { //!!! These lines cause the Whoops check below to return true. Writeln seems to zap the region. /* HLock((Handle)fCursorRgn); WrLblRect('fCursorRgn', (*fCursorRgn)->rgnBBox); fprintf(stderr, "\n"); HUnlock((Handle)fCursorRgn); */ } #endif if (qDebug && gIntenseDebugging &&!PtInRgn(globalMouse, fCursorRgn)) { fprintf(stderr, "Whoops, cursor region was not correctly calculated.\n"); fprintf(stderr, "global cursor = ", (char *) globalMouse); fprintf(stderr, " (*fCursorRgn)->rgnBBox = ", (char *) (*fCursorRgn)->rgnBBox); fprintf(stderr, "\n"); ProgramBreak("The cursor is not in the cursor region at end of TApplication.TrackCursor!"); } } /* TrackCursor */ //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::DoShowHelp(Point globalMouse, RgnHandle helpRgn) { if (HMIsBalloon()) { OSErr err = HMRemoveBalloon(); if (err != hmNoBalloonUp) FailOSErr(err); } this->GetDefaultHelpRgn(globalMouse, helpRgn); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal TView* TApplication::HandleHelp(Point globalMouse, RgnHandle helpRgn) { WindowPtr aWMgrWindow; TWindow* helpWindow; TView* helpView; VPoint windowVPt; Rect windowBounds; if (FindWindow(globalMouse, aWMgrWindow) == inContent) { helpWindow = this->WMgrToWindow(aWMgrWindow); if ((helpWindow) && helpWindow->HandlesHelp()) { VPoint windowVPt(globalMouse); helpWindow->SuperToLocal(windowVPt); helpView = helpWindow->HandleHelp(windowVPt, helpRgn); if ((helpView) && !EmptyRgn(helpRgn)) { VPoint viewVPt = gZeroVPt; helpView->LocalToWindow(viewVPt); helpWindow->LocalToSuper(viewVPt); OffsetRgn(helpRgn, (short) viewVPt.h, (short) viewVPt.v); } return helpView; } } else return NULL; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::TrackHelp(Point globalMouse) { TView * helpView; #if qDebugMsg if (PtInRgn(globalMouse, fHelpRgn)) { if (gIntenseDebugging && gTraceIdle) fprintf(stderr, "cursor is in help region\n"); } #endif this->InvalidateHelpRgn(); /* Find out if the cursor is in a window which handles help, and if so, call HandleHelp to find the view which claimed the cursor, and the region it computed. */ helpView = this->HandleHelp(globalMouse,fHelpRgn); if (EmptyRgn(fHelpRgn)) this->DoShowHelp(globalMouse, fHelpRgn); // Make sure the cursorpoint is included PtAndRgn(globalMouse, fHelpRgn); #if qDebugMsg if (gIntenseDebugging && gTraceIdle) if (fHelpRgn == NULL) fprintf(stderr, "fHelpRgn is NULL\n"); else { /* !!! See comment in TrackCursor HLock((Handle)(fHelpRgn)); WrLblRect('fHelpRgn', (*fHelpRgn)->rgnBBox); fprintf(stderr, "\n"); HUnlock((Handle)(fHelpRgn));*/ } #endif if (qDebug && gIntenseDebugging &&!PtInRgn(globalMouse, fHelpRgn)) { fprintf(stderr, "Whoops, help region was not correctly calculated.\n"); fprintf(stderr, "global cursor = ", (char *) globalMouse); fprintf(stderr, " (*fHelpRgn)->rgnBBox = ", (char *) (*fHelpRgn)->rgnBBox); fprintf(stderr, "\n"); ProgramBreak("The cursor is not in the help region at end of TApplication.TrackHelp!"); } } /* TrackHelp */ //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand class CTrackerMgr { // Fields protected: TApplication* fApplication; Point hysteresis; TTracker* fTracker; TView* fView; VPoint fAnchorPoint; VPoint fPreviousPoint; VPoint fNextPoint; VPoint fLastAnchorPoint; VPoint fLastPreviousPoint; VPoint fLastNextPoint; Boolean fDeskTopTracking; CGrafPort fDeskTopTrackingPort; GrafPtr fSavedPort; TrackPhase fTrackPhase; public: // Constructor CTrackerMgr(TApplication* theApplication, const VPoint& theMouse, Point theHysteresis, TTracker* theTracker) : fApplication(theApplication), fAnchorPoint(theMouse), hysteresis(theHysteresis), fTracker(theTracker) { fView = NULL; fSavedPort = NULL; fDeskTopTracking = FALSE; fTrackPhase = trackBegin; fPreviousPoint = theMouse; fNextPoint = theMouse; } // Methods TTracker* DoTracking(void); void CleanUpFocus(void); void DoFocus(void); void InstallTracker(TTracker* newTracker); void FeedbackOnce(Boolean mouseDidMove, Boolean turnItOn); void ConstrainOnce(Boolean didMouseMove); void TrackOnce(Boolean didMouseMove); }; //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand void CTrackerMgr::CleanUpFocus(void) { if (fDeskTopTracking) { if (qNeedsColorQD || gConfiguration.hasColorQD) CloseCPort(&fDeskTopTrackingPort); else ClosePort((GrafPtr) & fDeskTopTrackingPort); SetPort(fSavedPort); fDeskTopTracking = FALSE; } } //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand void CTrackerMgr::DoFocus(void) { if (fView) { if (fDeskTopTracking) CleanUpFocus(); if (!fView->Focus()) { #if qDebug ProgramBreak("TApplication.TrackMouse: Unable to focus fView."); #endif } } else { // focus on the desktop if (!fDeskTopTracking) { GetPort(fSavedPort); // In case we exit still focusedOnDeskTop if (qNeedsColorQD || gConfiguration.hasColorQD) OpenCPort(&fDeskTopTrackingPort); else OpenPort((GrafPtr) & fDeskTopTrackingPort); fDeskTopTracking = TRUE; } CopyRgn(GetGrayRgn(), fDeskTopTrackingPort.visRgn); fDeskTopTrackingPort.portRect = (*(fDeskTopTrackingPort.visRgn))->rgnBBox; fApplication->InvalidateFocus(); } } /* DoFocus */ //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand void CTrackerMgr::InstallTracker(TTracker* newTracker) { fTracker = newTracker; if (fTracker) { fView = fTracker->fView; DoFocus(); } } //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand void CTrackerMgr::ConstrainOnce(Boolean didMouseMove)// ??? fold this into TrackOnce ??? { if (fTracker && fTracker->fViewConstrain && (fView)) { VRect viewExtent; fView->GetExtent(viewExtent); fNextPoint.ConstrainTo(viewExtent); } if (fTracker && fTracker->fConstrainsMouse) fTracker->TrackConstrain(fTrackPhase, fAnchorPoint, fPreviousPoint, fNextPoint, didMouseMove); } //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand void CTrackerMgr::FeedbackOnce(Boolean mouseDidMove, Boolean turnItOn) { if (fTracker) { PenNormal(); PenMode(patXor); if (turnItOn) { fTracker->TrackFeedback(fTrackPhase, fAnchorPoint, fPreviousPoint, fNextPoint, mouseDidMove, turnItOn); // save these to turn it off with fLastAnchorPoint = fAnchorPoint; fLastPreviousPoint = fPreviousPoint; fLastNextPoint = fNextPoint; } else { fTracker->TrackFeedback(fTrackPhase, fLastAnchorPoint, fLastPreviousPoint, fLastNextPoint, mouseDidMove, turnItOn); } } } //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand void CTrackerMgr::TrackOnce(Boolean didMouseMove) { #if qDebug if (!fTracker) ProgramBreak("In TApplication.TrackMouse: fTracker == NULL"); #endif if (fTracker) { TTracker * newTracker = fTracker->TrackMouse(fTrackPhase, fAnchorPoint, fPreviousPoint, fNextPoint, didMouseMove); if (newTracker != fTracker) { fTracker = (TTracker *)(FreeIfObject(fTracker)); InstallTracker(newTracker); } else if (newTracker && (newTracker->fView != fView)) InstallTracker(newTracker); } } //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand TTracker* CTrackerMgr::DoTracking(void) { Boolean movedOnce = FALSE; this->InstallTracker(fTracker); this->ConstrainOnce(TRUE); fAnchorPoint = fNextPoint; fPreviousPoint = fNextPoint; // in case Constrain changed the fNextPoint; // guarantee that all 3 are the same on trackBegin this->TrackOnce(TRUE); fAnchorPoint = fNextPoint; fPreviousPoint = fNextPoint; // in case TrackMouse changed the fNextPoint; // guarantee that all 3 are the same on trackBegin this->FeedbackOnce(TRUE, TRUE); fTrackPhase = trackContinue; // supply trackphase to all interested parties while (fTracker && !fTracker->IsDoneTracking()) { Point theQDMouse; this->DoFocus(); GetMouse(theQDMouse); if (fView) fView->QDToViewPt(theQDMouse, fNextPoint); else fNextPoint = theQDMouse; if (!movedOnce) { this->ConstrainOnce(fPreviousPoint != fNextPoint);/* ensure that we are playing on a level field. */ VPoint amtMoved = fNextPoint - fAnchorPoint; if ((abs((int)amtMoved.h) >= hysteresis.h) || (abs((int)amtMoved.v) >= hysteresis.v)) movedOnce = TRUE; } VPoint delta = gZeroVPt; if (movedOnce || fTracker->fTrackNonMovement) { // ??? Problems with this: // delta might be non-zero but scrolling can't take place // because it is pinned at the end of the view // also might want some slop before scrolling TScroller* scroller = fTracker->fScroller; if (scroller && fView) { // convert fNextPoint to scroller coordinates VPoint mouseInScroller = fNextPoint; fView->LocalToWindow(mouseInScroller); scroller->WindowToLocal(mouseInScroller); // AutoScroll if the point is outside of the scroller's extent VRect autoScrollLimit; scroller->GetExtent(autoScrollLimit); if (!autoScrollLimit.Contains(mouseInScroller)) { scroller->AutoScroll(mouseInScroller, delta);// Get the amount to autoscroll fNextPoint += delta; } } this->ConstrainOnce(fPreviousPoint != fNextPoint); } Boolean willScroll = delta != gZeroVPt; Boolean didMove = fPreviousPoint != fNextPoint; this->FeedbackOnce(didMove || willScroll, FALSE); if (willScroll) { fTracker->AutoScroll(delta); // OK, now actually do the scrolling if (fView) fView->Update(); /* Keep synchronized. ScrollDraw only invalidated */ this->DoFocus(); // the focus changed } this->TrackOnce(didMove); // ??? add || willScroll ??? this->FeedbackOnce(didMove || willScroll, TRUE); fPreviousPoint = fNextPoint; } fTrackPhase = trackEnd; // supply trackphase to all interested parties this->DoFocus(); EventRecord peekEvent; if (!movedOnce) fNextPoint = fPreviousPoint; /* normally same as original mouse down; we don't use fAnchorPoint in case someone has changed that -- it is more likely that an app would change fAnchorPoint than fPreviousPoint */ else if (OSEventAvail(mUpMask + mDownMask, peekEvent)) { Point theQDMouse = peekEvent.where; if (fView) { GlobalToLocal(theQDMouse); fView->QDToViewPt(theQDMouse, fNextPoint); } else fNextPoint = theQDMouse; this->ConstrainOnce(TRUE); } // else we use the last known mouse position this->FeedbackOnce(TRUE, FALSE); this->TrackOnce(TRUE); this->CleanUpFocus(); return fTracker; } //-------------------------------------------------------------------------------------------------- #pragma segment MADoCommand pascal TTracker* TApplication::TrackMouse(const VPoint& theMouse, Point hysteresis, TTracker* theCommand) { CTrackerMgr aCTrackerMgr(this, theMouse, hysteresis, theCommand); return aCTrackerMgr.DoTracking(); } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal void TApplication::UpdateAllWindows(void) { TToolboxEvent * event; ++fEventLevel; while(event = this->GetEvent(updateMask + activMask, 0, NULL)) event->Process(); --fEventLevel; } //-------------------------------------------------------------------------------------------------- #pragma segment MAApplicationRes pascal TWindow* TApplication::WMgrToWindow(WindowPtr aWMgrWindow) { /* Make an IsObject test too because some slimedog may have created a window in our world and the refcon wouldn't be an object. Since this is the only place in MacApp that we get asked to do something to a ToolBox structure where we don't _know_ that we created the structure we need to be especially careful here. ??? Perhaps in the future we should use a dictionary to make the windowPtr to TWindow association for us. */ if (aWMgrWindow && (qNeedsProcessMgr || gConfiguration.hasProcessMgr ||!this->IsDeskAccessory(aWMgrWindow)) && IsObject((TObject *)GetWRefCon(aWMgrWindow))) return (TWindow *)(GetWRefCon(aWMgrWindow)); else return NULL; } //-------------------------------------------------------------------------------------------------- #pragma segment MAOpen pascal void TApplication::DoMakeViewServer(void) { TViewServer* aViewServer = new TViewServer; aViewServer->IViewServer(); // assigns the global reference }